2012-01-18 33 views
2

私はCreateProcessWで作成した プロセスから標準出力/エラーを読み取る方法を理解しようとしています。私は はググ、ドキュメントを見て、このリストを検索するが、私はまだ良いのポインタ/サンプル を見つけられませんでした:)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

:プログラムの

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/en-us/library/windows/desktop/hh448381%28v=vs.85%29.aspx)関数を例として使用できます。 –

+0

お返事ありがとうございました!ええ、私は方法自体を集めて出力を与えません。 StartupInfoには次のものが含まれます。 public HANDLE hStdInput; public HANDLE hStdOutput; public HANDLE hStdError; しかし、私はどのようにハンドルをJava側で消費できるものにマップするのか分かりません。私はそれが私がJava側で読むことができるいくつかのストリームになると思います。また、私は厳密にそれらのフィールドを正しく割り当てる方法を知らない... 私はGetProcessInformationに関するご意見をお聞きします。あなたが他のポインタを持っているなら、私はそのエリアでかなり緑色であるので、返信してください。再度、感謝します! – Szczepan

+0

申し訳ありませんが、私たちは 'ProcessInformation'構造または' GetProcessInformation'関数から何か(出力を得ること)を達成できないようです。私が下に与えた解決策を参照してください –

答えて

6

CreateProcess関数で作成されたプロセスのコンソールに書き込むには、子プロセスを作成し、匿名パイプを使用して子プロセスの標準入力および出力ハンドルをリダイレクトすることを推奨します。

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プログラムには2つの引数が必要です。(1)コマンドライン。 (2)入力ファイル。

使用例:私は `CreateProcess`を考えていない

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

+0

私はあなたがKernel32を実装する必要はないと思う。私はJNA(4.0)の最新バージョンをダウンロードしたばかりで、すでにKernel32.CreateProcessというメソッドがあります。 http://twall.github.io/jna/3.3.0/javadoc/com/sun/jna/platform/win32/Kernel32.htmlを参照してください。 –

関連する問題