2012-01-18 130 views
2

我想知道如何從我用CreateProcessW創建的 進程中讀取標準out/err。我看了看文檔, 一派,搜索這個名單,但我沒有找到好的指針/樣品 尚未:)如何在使用jna和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); 

所以...我怎麼能抓住那個過程的輸出?任何人都已經做到了,並且關心分享樣品?

感謝球員提前提供任何幫助。

+0

我不認爲'CreateProcess':

程序的
java -jar RunTest.jar "C:\\Program Files\\Java\\jre6\\bin\\java.exe -version" "C:\\Documents and Settings\\Administrator\\Desktop\\test.txt" 

輸出示例將返回一個處理信息的對象,因爲規範說它返回一個BOOL值。您應該調用該函數在調用它之後立即在其參數中引用的「ProcessInformation」結構的狀態。在規範中,它說'lpProcessInformation [out]'是一個指向PROCESS_INFORMATION結構的指針,它接收關於新進程的標識信息。或者,您可以使用Kernel32的['GetProcessInformation'](http://msdn.microsoft.com/zh-cn/library/windows/desktop/hh448381%28v=vs.85%29.aspx)函數和一個示例。 – 2012-01-19 01:22:55

+0

非常感謝您的回覆!是的,我收集的方法本身不會給出輸出。 StartupInfo包含(除其他外): public HANDLE hStdInput; public HANDLE hStdOutput; public HANDLE hStdError; 但是,我不確定如何將HANDLE映射到可以在java端使用的東西。我希望這將是我可以在Java端閱讀的一些流。此外,我不嚴格知道如何正確分配這些字段... 我會深入瞭解GetProcessInformation的建議。如果您有其他指針,請回復,因爲我在該地區非常綠。再次感謝! – Szczepan 2012-01-19 23:50:46

+0

對不起,我們似乎無法從'ProcessInformation''結構或'GetProcessInformation'函數獲得任何東西(獲取輸出)。請參閱我在 – 2012-01-20 07:30:00

回答

6

要向使用CreateProcess函數創建的進程寫入控制檯,MSDN建議創建子進程並使用匿名管道重定向子進程的標準輸入和輸出句柄。

Creating a Child Process with Redirected Input and Output

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

/* 
    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(); 
} 

然後,主部:

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; 
     } 
    } 
    /** 
    * {@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)輸入文件。

用法示例:

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

+0

以下給出的解決方案。我非常感謝徹底的答覆!這裏是我的原始問題以供參考:http://stackoverflow.com/questions/9012639/java-process-inputstream-stuck – Szczepan 2012-01-26 00:52:16

+0

我認爲你不需要實現Kernel32。我剛剛下載了最新版本的JNA(4.0),它已經有一個名爲Kernel32.CreateProcess的方法。請參閱http://twall.github.io/jna/3.3.0/javadoc/com/sun/jna/platform/win32/Kernel32.html – 2013-11-11 17:10:24

相關問題