更新时间:2022-02-15 23:13:28
已解决!
I need to write the fields to memory before pass the Structures
to the methods call.
这是最终代码(搜索注释// <<<< WRITE THE FIELDS TO NATIVE MEMORY
):
This is the final code (search for comment // <<<< WRITE THE FIELDS TO NATIVE MEMORY
):
import java.util.Arrays;
import java.util.List;
import java.util.Scanner;
import java.util.stream.Collectors;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.platform.win32.WinBase;
import com.sun.jna.platform.win32.WinDef;
import com.sun.jna.platform.win32.WinNT;
import com.sun.jna.platform.win32.WinNT.HANDLE;
import com.sun.jna.ptr.IntByReference;
import com.sun.jna.win32.W32APIOptions;
public final class ProcessChildAttached {
public static abstract class Structure extends com.sun.jna.Structure {
public Structure() {
super();
}
public Structure(Pointer p) {
super(p);
}
private List<String> fields;
protected Class<? extends Structure> getFieldsClass() {
Class<? extends Structure> ret = this.getClass();
if (ByReference.class.isAssignableFrom(ret) && com.sun.jna.Structure.class.isAssignableFrom(ret.getSuperclass())) {
ret = (Class<? extends Structure>) ret.getSuperclass();
}
return ret;
}
@Override
protected List<String> getFieldOrder() {
if (fields == null) {
fields = Arrays.stream(getFieldsClass().getDeclaredFields()).map(df -> df.getName()).collect(Collectors.toList());
}
return fields;
}
}
static interface Kernel32 extends com.sun.jna.platform.win32.Kernel32 {
Kernel32 INSTANCE = Native.loadLibrary("kernel32", Kernel32.class, W32APIOptions.UNICODE_OPTIONS);
WinNT.HANDLE CreateJobObject(WinBase.SECURITY_ATTRIBUTES attrs, String name);
boolean SetInformationJobObject(HANDLE hJob, int JobObjectInfoClass, Pointer lpJobObjectInfo, int cbJobObjectInfoLength);
boolean AssignProcessToJobObject(HANDLE hJob, HANDLE hProcess);
boolean TerminateJobObject(HANDLE hJob, long uExitCode);
int ResumeThread(HANDLE hThread);
// 0x00000800
int JOB_OBJECT_LIMIT_BREAKAWAY_OK = 2048;
// 0x00002000
int JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE = 8192;
// see SetInformationJobObject at msdn
int JobObjectExtendedLimitInformation = 9;
// see SetInformationJobObject at msdn
int JobObjectBasicUIRestrictions = 4;
// 0x00000020
int JOB_OBJECT_UILIMIT_GLOBALATOMS = 0x00000020;
// 0x00000004
int CREATE_SUSPENDED = 4;
// 0x01000000
int CREATE_BREAKAWAY_FROM_JOB = 16777216;
static class JOBJECT_BASIC_LIMIT_INFORMATION extends Structure {
public LARGE_INTEGER PerProcessUserTimeLimit;
public LARGE_INTEGER PerJobUserTimeLimit;
public int LimitFlags;
public SIZE_T MinimumWorkingSetSize;
public SIZE_T MaximumWorkingSetSize;
public int ActiveProcessLimit;
public ULONG_PTR Affinity;
public int PriorityClass;
public int SchedulingClass;
}
static class IO_COUNTERS extends Structure {
public ULONGLONG ReadOperationCount;
public ULONGLONG WriteOperationCount;
public ULONGLONG OtherOperationCount;
public ULONGLONG ReadTransferCount;
public ULONGLONG WriteTransferCount;
public ULONGLONG OtherTransferCount;
}
static class JOBJECT_EXTENDED_LIMIT_INFORMATION extends Structure {
public JOBJECT_EXTENDED_LIMIT_INFORMATION() {
}
public JOBJECT_EXTENDED_LIMIT_INFORMATION(Pointer memory) {
super(memory);
}
public JOBJECT_BASIC_LIMIT_INFORMATION BasicLimitInformation;
public IO_COUNTERS IoInfo;
public SIZE_T ProcessMemoryLimit;
public SIZE_T JobMemoryLimit;
public SIZE_T PeakProcessMemoryUsed;
public SIZE_T PeakJobMemoryUsed;
public static class ByReference extends JOBJECT_EXTENDED_LIMIT_INFORMATION implements Structure.ByReference {
public ByReference() {
}
public ByReference(Pointer memory) {
super(memory);
}
}
}
static class JOBOBJECT_BASIC_UI_RESTRICTIONS extends Structure {
public JOBOBJECT_BASIC_UI_RESTRICTIONS() {
}
public JOBOBJECT_BASIC_UI_RESTRICTIONS(Pointer memory) {
super(memory);
}
public int UIRestrictionsClass;
public static class ByReference extends JOBOBJECT_BASIC_UI_RESTRICTIONS implements Structure.ByReference {
public ByReference() {
}
public ByReference(Pointer memory) {
super(memory);
}
}
}
}
private Kernel32 kernel32 = Kernel32.INSTANCE;
private String cmd;
private String workingDirectory;
private HANDLE hJob;
private WinBase.PROCESS_INFORMATION.ByReference pi;
public ProcessChildAttached(String cmd, String workingDirectory) {
this.cmd = cmd;
this.workingDirectory = workingDirectory;
}
public void start() {
WinBase.STARTUPINFO si = new WinBase.STARTUPINFO();
si.clear();
pi = new WinBase.PROCESS_INFORMATION.ByReference();
pi.clear();
Kernel32.JOBJECT_EXTENDED_LIMIT_INFORMATION jeli = new Kernel32.JOBJECT_EXTENDED_LIMIT_INFORMATION.ByReference();
jeli.clear();
Kernel32.JOBOBJECT_BASIC_UI_RESTRICTIONS uli = new Kernel32.JOBOBJECT_BASIC_UI_RESTRICTIONS.ByReference();
uli.clear();
// Call SetHandleInformation. Take a look in SocketLock.cs
hJob = kernel32.CreateJobObject(null, null);
if (hJob.getPointer() == null) {
throw new RuntimeException("Cannot create job object: " + kernel32.GetLastError());
}
// Hopefully, Windows will kill the job automatically if this process dies
// But beware! Process Explorer can break this by keeping open a handle to all jobs!
// http://forum.sysinternals.com/forum_posts.asp?TID=4094
jeli.BasicLimitInformation.LimitFlags = Kernel32.JOB_OBJECT_LIMIT_BREAKAWAY_OK | Kernel32.JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
jeli.write(); // <<<< WRITE THE FIELDS TO NATIVE MEMORY
if (!kernel32.SetInformationJobObject(hJob, Kernel32.JobObjectExtendedLimitInformation, jeli.getPointer(), jeli.size())) {
throw new RuntimeException("Unable to set extended limit information on the job object: " + kernel32.GetLastError());
}
// crete job in sandbox with own global atom table
uli.UIRestrictionsClass = Kernel32.JOB_OBJECT_UILIMIT_GLOBALATOMS;
uli.write(); // <<<< WRITE THE FIELDS TO NATIVE MEMORY
if (!kernel32.SetInformationJobObject(hJob, Kernel32.JobObjectBasicUIRestrictions, uli.getPointer(), uli.size())) {
throw new RuntimeException("Unable to set ui limit information on the job object: " + kernel32.GetLastError());
}
WinDef.DWORD creationFlags = new WinDef.DWORD(Kernel32.CREATE_SUSPENDED | // Suspend so we can add to job
Kernel32.CREATE_BREAKAWAY_FROM_JOB | // Allow ourselves to breakaway from Vista's PCA if necessary
Kernel32.CREATE_NEW_PROCESS_GROUP);
// Start the child process
boolean result = kernel32.CreateProcess(null, // No module name (use command line).
cmd, // Command line.
null, // Process handle not inheritable.
null, // Thread handle not inheritable.
false, // Set handle inheritance to FALSE.
creationFlags, // Set creation flags
null, // Use parent's environment block.
workingDirectory, // Use provided working directory, parent's directory if null.
si, // Pointer to STARTUPINFO structure.
pi); // Pointer to PROCESS_INFORMATION structure.
if (!result) {
throw new RuntimeException("Failed to create the process: " + kernel32.GetLastError());
}
if (!kernel32.AssignProcessToJobObject(hJob, pi.hProcess)) {
throw new RuntimeException("Cannot assign process to job: " + kernel32.GetLastError());
}
if (kernel32.ResumeThread(pi.hThread) <= 0) {
throw new RuntimeException("Cannot resume thread: " + kernel32.GetLastError());
}
kernel32.CloseHandle(pi.hThread);
// Kernel32.CloseHandle(pi.hProcess);
}
public boolean isRunning() {
return hJob != null;
}
public void destroy() {
if (!isRunning()) {
return;
}
kernel32.CloseHandle(pi.hProcess);
pi = null;
// This seems a trifle brutal. Oh well. Brutal it is.
kernel32.TerminateJobObject(hJob, 666);
kernel32.CloseHandle(hJob);
hJob = null;
}
public int waitFor() {
if (isRunning()) {
kernel32.WaitForSingleObject(pi.hProcess, Kernel32.INFINITE);
IntByReference exitCode = new IntByReference();
if (kernel32.GetExitCodeProcess(pi.hProcess, exitCode)) {
return exitCode.getValue();
}
destroy();
}
return -1;
}
}