I'm new to JNA and upon attempting my first program to list all processes on Windows I've run into a bit of trouble. For some reason, I get the following output:
[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?? ]
...
The process identifiers were valid and were currently running on my system during the snapshot, but for some reason the strings got corrupted. Several other similar examples on StackOverflow gave me the same result. Do I need to specify something new in the latest version of JNA to get such a procedure to work?
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;
}
}
My code is based heavily off of the MSDN example featured here.
You're missing options to Native.loadLibrary
to tell JNA to automatically map to Process32FirstW
(W32APIOptions.DEFAULT_OPTIONS
will do that for you). See how JNA itself loads the kernel32
library.
The definition of Process32First
included with JNA's platform.jar
will actually only work with the unicode (-W
) version due to the definition of the PROCESSENTRY32
structure, which uses Java char
for the filename. The reason you're getting junk is that the encoded byte array of the "ANSI" version has been read into a Java char
array. Native.toString()
is attempting to read from that array, unaware that the data was originally encoded bytes.