繁体   English   中英

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

[英]how to get the process output when using jna and 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

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)输入文件。

用法示例:

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM