Search code examples
javajna

JNA Windows get process path


I found this code on stackoverflow that explain how to get all running process on windows, this get name and pid

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));
    }
} finally {
    kernel32.CloseHandle(snapshot);
}

My question is: how can i get the process path?


Solution

  • Using JNA, you need to define the MODULEENTRY32 structure and map some required functions :

    import java.util.Arrays;
    import java.util.List;
    
    import com.sun.jna.Native;
    import com.sun.jna.Pointer;
    import com.sun.jna.Structure;
    import com.sun.jna.platform.win32.Kernel32;
    import com.sun.jna.platform.win32.WinDef;
    import com.sun.jna.win32.W32APIOptions;
    
    public interface ProcessPathKernel32 extends Kernel32 {
        class MODULEENTRY32 extends Structure {
            public static class ByReference extends MODULEENTRY32 implements Structure.ByReference {
                public ByReference() {
                }
    
                public ByReference(Pointer memory) {
                    super(memory);
                }
            }
            public MODULEENTRY32() {
                dwSize = new WinDef.DWORD(size());
            }
    
            public MODULEENTRY32(Pointer memory) {
                super(memory);
                read();
            }
    
    
            public DWORD dwSize;
            public DWORD th32ModuleID;
            public DWORD th32ProcessID;
            public DWORD GlblcntUsage;
            public DWORD ProccntUsage;
            public Pointer modBaseAddr;
            public DWORD modBaseSize;
            public HMODULE hModule;
            public char[] szModule = new char[255+1]; // MAX_MODULE_NAME32
            public char[] szExePath = new char[MAX_PATH];
            public String szModule() { return Native.toString(this.szModule); }
            public String szExePath() { return Native.toString(this.szExePath); }
            @Override
            protected List<String> getFieldOrder() {
                return Arrays.asList(new String[] {
                    "dwSize", "th32ModuleID", "th32ProcessID", "GlblcntUsage", "ProccntUsage", "modBaseAddr", "modBaseSize", "hModule", "szModule", "szExePath"
                });
            }
        }
    
        ProcessPathKernel32 INSTANCE = (ProcessPathKernel32)Native.loadLibrary(ProcessPathKernel32.class, W32APIOptions.UNICODE_OPTIONS);
        boolean Module32First(HANDLE hSnapshot, MODULEENTRY32.ByReference lpme);
        boolean Module32Next(HANDLE hSnapshot, MODULEENTRY32.ByReference lpme);
    }
    

    then you retrieve the processes and for each PID, retrieve the Module information (the path of the module is now available). If running from a 32bits process then you only get the Module information from 32bits processes (the path will be blank for the 64bits processes).

    import com.sun.jna.Native;
    import com.sun.jna.platform.win32.Kernel32;
    import com.sun.jna.platform.win32.Kernel32Util;
    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;
    
    public class ProcessPathAll {
    
        public static void main(String ... args) {
            Kernel32 kernel32 = (Kernel32) Native.loadLibrary(Kernel32.class, W32APIOptions.DEFAULT_OPTIONS);
            Tlhelp32.PROCESSENTRY32.ByReference processEntry = new Tlhelp32.PROCESSENTRY32.ByReference();
            WinNT.HANDLE processSnapshot = 
                    kernel32.CreateToolhelp32Snapshot(Tlhelp32.TH32CS_SNAPPROCESS, new WinDef.DWORD(0));
            try {
    
                while (kernel32.Process32Next(processSnapshot, processEntry)) {
                    // looks for a specific process
                    // if (Native.toString(processEntry.szExeFile).equalsIgnoreCase("textpad.exe")) {
                    System.out.print(processEntry.th32ProcessID + "\t" + Native.toString(processEntry.szExeFile) + "\t");
                    WinNT.HANDLE moduleSnapshot = 
                        kernel32.CreateToolhelp32Snapshot(Tlhelp32.TH32CS_SNAPMODULE, processEntry.th32ProcessID);
                    try {
                         ProcessPathKernel32.MODULEENTRY32.ByReference me = new ProcessPathKernel32.MODULEENTRY32.ByReference();
                         ProcessPathKernel32.INSTANCE.Module32First(moduleSnapshot, me);
                         System.out.print(": " + me.szExePath() );
                         System.out.println();
                     }
                     finally {
                         kernel32.CloseHandle(moduleSnapshot);
                     }
                    // }
                }
            } 
            finally {
                kernel32.CloseHandle(processSnapshot);
            }
        }
    }