为了向使用
CreateProcess功能创建的进程写入控制台,MSDN建议创建一个子进程并使用匿名管道来重定向该子进程的标准输入和输出句柄。
创建具有重定向输入和输出的子进程
由于JNA 3.3.0平台未包含我们需要的所有Kernel32函数,因此我们需要提供所需的JNA接口,如下所示:(注意JNA 4.0
为您提供了Kernel32)
Kernel32.java:
import java.util.HashMap;import java.util.Map;import com.sun.jna.Library;import com.sun.jna.Native;import com.sun.jna.Pointer;import com.sun.jna.win32.StdCallLibrary;import com.sun.jna.win32.W32APIFunctionMapper;import com.sun.jna.win32.W32APITypeMapper;import com.sun.jna.platform.win32.Winbase.SECURITY_ATTRIBUTES;import com.sun.jna.platform.win32.Winbase.STARTUPINFO;import com.sun.jna.platform.win32.WinDef.DWORD;import com.sun.jna.platform.win32.Winbase.PROCESS_INFORMATION;import com.sun.jna.platform.win32.WinNT.HANDLE;public interface Kernel32 extends StdCallLibrary { final static Map<String, Object> WIN32API_OPTIONS = new HashMap<String, Object>() { private static final long serialVersionUID = 1L; { put(Library.OPTION_FUNCTION_MAPPER, W32APIFunctionMapper.UNICODE); put(Library.OPTION_TYPE_MAPPER, W32APITypeMapper.UNICODE); } }; public Kernel32 INSTANCE = (Kernel32) Native.loadLibrary("Kernel32", Kernel32.class, WIN32API_OPTIONS); public boolean CreateProcess( String lpApplicationName, String lpCommandLine, SECURITY_ATTRIBUTES lpProcessAttributes, SECURITY_ATTRIBUTES lpThreadAttributes, boolean bInheritHandles, DWORD dwCreationFlags, Pointer lpEnvironment, String lpCurrentDirectory, STARTUPINFO lpStartupInfo, PROCESS_INFORMATION lpProcessInformation ); public HANDLE GetStdHandle(DWORD nStdHandle); public int GetLastError();}然后,主要部分:
RunTest.java:
import java.nio.ByteBuffer;import com.sun.jna.Native;import com.sun.jna.Pointer;import com.sun.jna.platform.win32.Winbase.PROCESS_INFORMATION;import com.sun.jna.platform.win32.Winbase.SECURITY_ATTRIBUTES;import com.sun.jna.platform.win32.Winbase.STARTUPINFO;import com.sun.jna.platform.win32.WinDef.DWORD;import com.sun.jna.platform.win32.WinNT.HANDLE;import com.sun.jna.platform.win32.WinNT.HANDLEByReference;import com.sun.jna.ptr.IntByReference;public class RunTest { static HANDLEByReference childStdInRead = new HANDLEByReference(); static HANDLEByReference childStdInWrite = new HANDLEByReference(); static HANDLEByReference childStdOutRead = new HANDLEByReference(); static HANDLEByReference childStdOutWrite = new HANDLEByReference(); static final int HANDLE_FLAG_INHERIT = 0x00000001; static final int HANDLE_FLAG_PROTECT_FROM_CLOSE = 0x00000002; static final int BUFSIZE = 4096; static final int GENERIC_READ = 0x80000000; static final int FILE_ATTRIBUTE_READonLY = 1; private static final int OPEN_EXISTING = 3; private static final DWORD STD_OUTPUT_HANDLE = new DWORd(-11); private static final int STARTF_USESTDHANDLES = 0x00000100; static HANDLE inputFile = null; static void createChildProcess(String cmd){ String szCmdline = cmd; PROCESS_INFORMATION processInformation = new PROCESS_INFORMATION(); STARTUPINFO startupInfo = new STARTUPINFO(); startupInfo.cb = new DWORd(processInformation.size()); startupInfo.hStdError = childStdOutWrite.getValue(); startupInfo.hStdOutput = childStdOutWrite.getValue(); startupInfo.hStdInput = childStdInRead.getValue(); startupInfo.dwFlags |= STARTF_USESTDHANDLES; // Create the child process. if (!Kernel32.INSTANCE.CreateProcess( null, szCmdline, null, null, true, new DWORd(0x00000020), null, null, startupInfo, processInformation)){ System.err.println(Kernel32.INSTANCE.GetLastError()); } else { com.sun.jna.platform.win32.Kernel32.INSTANCE.WaitForSingleObject(processInformation.hProcess, 0xFFFFFFFF); com.sun.jna.platform.win32.Kernel32.INSTANCE.CloseHandle(processInformation.hProcess); com.sun.jna.platform.win32.Kernel32.INSTANCE.CloseHandle(processInformation.hThread); } } static void WriteToPipe() // Read from a file and write its contents to the pipe for the child's STDIN. // Stop when there is no more data. { IntByReference dwRead = new IntByReference(); IntByReference dwWritten = new IntByReference(); ByteBuffer buf = ByteBuffer.allocateDirect(BUFSIZE); Pointer data = Native.getDirectBufferPointer(buf); boolean bSuccess = true; for (;;) { bSuccess = com.sun.jna.platform.win32.Kernel32.INSTANCE.ReadFile(inputFile, buf, BUFSIZE, dwRead, null); if ( ! bSuccess || dwRead.getValue() == 0 ) break; bSuccess = com.sun.jna.platform.win32.Kernel32.INSTANCE.WriteFile(childStdInWrite.getValue(), data.getByteArray(0, BUFSIZE), dwRead.getValue(), dwWritten, null); if ( ! bSuccess ) break; } // Close the pipe handle so the child process stops reading. if (!com.sun.jna.platform.win32.Kernel32.INSTANCE.CloseHandle(childStdInWrite.getValue())){ System.err.println(Kernel32.INSTANCE.GetLastError()); } } static void ReadFromPipe() // Read output from the child process's pipe for STDOUT // and write to the parent process's pipe for STDOUT. // Stop when there is no more data. { IntByReference dwRead = new IntByReference(); IntByReference dwWritten = new IntByReference(); ByteBuffer buf = ByteBuffer.allocateDirect(BUFSIZE); Pointer data = Native.getDirectBufferPointer(buf); boolean bSuccess = true; HANDLE hParentStdOut = Kernel32.INSTANCE.GetStdHandle(STD_OUTPUT_HANDLE); // Close the write end of the pipe before reading from the // read end of the pipe, to control child process execution. // The pipe is assumed to have enough buffer space to hold the // data the child process has already written to it. if (!com.sun.jna.platform.win32.Kernel32.INSTANCE.CloseHandle(childStdOutWrite.getValue())){ System.err.println(Kernel32.INSTANCE.GetLastError()); } for (;;) { bSuccess = com.sun.jna.platform.win32.Kernel32.INSTANCE.ReadFile( childStdOutRead.getValue(), buf, BUFSIZE, dwRead, null); if( ! bSuccess || dwRead.getValue() == 0 ) break; bSuccess = com.sun.jna.platform.win32.Kernel32.INSTANCE.WriteFile(hParentStdOut, data.getByteArray(0, BUFSIZE), dwRead.getValue(), dwWritten, null); if (! bSuccess ) break; } } public static void main(String[] args) { if (args.length < 1) { System.err.println("Please specify a command.n"); System.exit(1); } if (args.length < 2) { System.err.println("Please specify an input file.n"); System.exit(1); } SECURITY_ATTRIBUTES saAttr = new SECURITY_ATTRIBUTES(); saAttr.dwLength = new DWORd(saAttr.size()); saAttr.bInheritHandle = true; saAttr.lpSecurityDescriptor = null; // Create a pipe for the child process's STDOUT. if (!com.sun.jna.platform.win32.Kernel32.INSTANCE.CreatePipe(childStdOutRead, childStdOutWrite, saAttr, 0)){ System.err.println(Kernel32.INSTANCE.GetLastError()); } // Ensure the read handle to the pipe for STDOUT is not inherited. if (!com.sun.jna.platform.win32.Kernel32.INSTANCE.SetHandleInformation(childStdOutRead.getValue(), HANDLE_FLAG_INHERIT, 0)){ System.err.println(Kernel32.INSTANCE.GetLastError());; } // Create a pipe for the child process's STDIN. if (!com.sun.jna.platform.win32.Kernel32.INSTANCE.CreatePipe(childStdInRead, childStdInWrite, saAttr, 0)){ System.err.println(Kernel32.INSTANCE.GetLastError()); } // Ensure the write handle to the pipe for STDIN is not inherited. if (!com.sun.jna.platform.win32.Kernel32.INSTANCE.SetHandleInformation(childStdInWrite.getValue(), HANDLE_FLAG_INHERIT, 0)){ System.err.println(Kernel32.INSTANCE.GetLastError());; } createChildProcess(args[0]); inputFile = com.sun.jna.platform.win32.Kernel32.INSTANCE.CreateFile( args[1], GENERIC_READ, 0, null, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, null); // Write to the pipe that is the standard input for a child process. // Data is written to the pipe's buffers, so it is not necessary to wait // until the child process is running before writing data.WriteToPipe(); System.out.println( "n->Contents of ""+args[1]+"" written to child STDIN pipe.n"); // Read from pipe that is the standard output for child process.System.out.println( "n->Contents of child process STDOUT:nn" + args[1]);ReadFromPipe();System.out.println("n->End of parent execution.n"); // The remaining open handles are cleaned up when this process terminates. // To avoid resource leaks in a larger application, close handles explicitly. }}原始的MSDN程序仅要求一个参数。但是,修改后的Runtest Java程序将需要两个参数:(1)命令行;(2)输入文件。
用法示例:
java -jar RunTest.jar "C:\Program Files\Java\jre6\bin\java.exe -version" "C:\documents and Settings\Administrator\Desktop\test.txt"
程序的示例输出:
->Contents of "C:\documents and Settings\Administrator\Desktop\test.txt" written to child STDIN pipe.->Contents of child process STDOUT:C:\documents and Settings\Administrator\Desktop\test.txtjava version "1.6.0_29"Java(TM) SE Runtime Environment (build 1.6.0_29-b11)Java HotSpot(TM) Client VM (build 20.4-b02, mixed mode, sharing)->End of parent execution.
如果要查看详细版本,请…
WindowsXPProcess.java



