使用jna和CreateProcessW时如何获取进程输出

我试图弄清楚如何从用CreateProcessW创建的过程中读取标准输出/错误。我看了看文档,用谷歌搜索了这个列表,但是我还没有找到好的指针/样本:)

到目前为止,这是我想到的(在Windows上运行良好,这是我的Java代码中的相关代码段):

Kernel32 kernel32 = (Kernel32) Native.loadLibrary("kernel32", Kernel32.class); 

Kernel32.StartupInfo startupInfo = new Kernel32.StartupInfo();

Kernel32.ProcessInfo processInformation = new Kernel32.ProcessInfo();

if (!kernel32.CreateProcessW(null, new WString(command), null, null, false,

DETACHED_PROCESS, null, new WString(dir.getAbsolutePath()), startupInfo,

processInformation)) {

throw new IOException("Could not start process. Errno: " +

kernel32.GetLastError());

}

kernel32.CloseHandle(processInformation.hProcess);

kernel32.CloseHandle(processInformation.hThread);

那么…我该如何获取该过程的输出?任何人都已经做到了,并愿意分享一个样本吗?

谢谢大家的任何帮助。

回答:

为了向使用CreateProcess功能创建的进程写入控制台,MSDN建议创建一个子进程并使用匿名管道来重定向该子进程的标准输入和输出句柄。

创建具有重定向输入和输出的子进程

由于JNA 3.3.0平台未包含我们需要的所有Kernel32函数,因此我们需要提供所需的JNA接口,如下所示:(注意JNA 4.0

为您提供了Kernel32)

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);

/*

BOOL WINAPI CreateProcess(

__in_opt LPCTSTR lpApplicationName,

__inout_opt LPTSTR lpCommandLine,

__in_opt LPSECURITY_ATTRIBUTES lpProcessAttributes,

__in_opt LPSECURITY_ATTRIBUTES lpThreadAttributes,

__in BOOL bInheritHandles,

__in DWORD dwCreationFlags,

__in_opt LPVOID lpEnvironment,

__in_opt LPCTSTR lpCurrentDirectory,

__in LPSTARTUPINFO lpStartupInfo,

__out LPPROCESS_INFORMATION lpProcessInformation

);

*/

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();

}

然后,主要部分:

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;

}

}

/**

* {@link http://msdn.microsoft.com/en-us/library/windows/desktop/ms682499(v=vs.85).aspx}

*/

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:\n\n" + 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.txt

java 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

以上是 使用jna和CreateProcessW时如何获取进程输出 的全部内容, 来源链接: utcz.com/qa/404239.html

回到顶部