调用一个控制台程序并取得其输出

 
在程序设计中,有时候需要调用一些控制台程序并取得其在控制台上的输出,如VS的IDE就调用了cl.exe、link.exe等控制台的程序,并可将这些程序的输出在IDE中显示出来。
曾经很迷惑这个功能的实现,直到有一天看到下面的参考代码才恍然大悟,原来一切都这么简单,只不过用了CreatePipe、CreateProcess、ReadFile寥寥几个函数而已。特此记下以供参考。
#include "Stdafx.h"
 
#include <windows.h>
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
 
 
/* protos */
 
DWORD WINAPI ReadFromPipe(LPVOID args);
 
/* globals */
 
#define CHUNK 25
#define STATICBUFFERSIZE    1000
typedef struct {
    HANDLE pipe;
    char buffer[STATICBUFFERSIZE];
} pipeinfo;
 
pipeinfo Out = {INVALID_HANDLE_VALUE, '/0'};
pipeinfo Err = {INVALID_HANDLE_VALUE, '/0'};
 
int
main(
    int argc,
    char *argv[])
{
     if(argc < 2)
     {
         printf("pipetest ??");
         return 0;
     }
 
    STARTUPINFO si;
    PROCESS_INFORMATION pi;
    SECURITY_ATTRIBUTES sa;
    DWORD threadID;
    char msg[300];
    BOOL ok;
    HANDLE hProcess, h, pipeThreads[2];
    char cmdline[100];
 
    hProcess = GetCurrentProcess();
 
    ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
    ZeroMemory(&si, sizeof(STARTUPINFO));
    si.cb = sizeof(STARTUPINFO);
    si.dwFlags   = STARTF_USESTDHANDLES;
    si.hStdInput = INVALID_HANDLE_VALUE;
 
    ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES));
    sa.nLength = sizeof(SECURITY_ATTRIBUTES);
    sa.lpSecurityDescriptor = NULL;
    sa.bInheritHandle = TRUE;
 
    /*
     * Create a non-inheritible pipe.
     */
 
    CreatePipe(&Out.pipe, &h, &sa, 0);
 
    /*
     * Dupe the write side, make it inheritible, and close the original.
     */
 
    DuplicateHandle(hProcess, h, hProcess, &si.hStdOutput, 0, TRUE,
         DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
 
    /*
     * Same as above, but for the error side.
     */
 
    CreatePipe(&Err.pipe, &h, &sa, 0);
    DuplicateHandle(hProcess, h, hProcess, &si.hStdError, 0, TRUE,
         DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
 
 
     strcpy(cmdline, "");
     for(int i = 1; i < argc; i++)
     {
         strcat(cmdline, argv[i]);
         strcat(cmdline, " ");
     }
 
    ok = CreateProcess(
         NULL,     /* Module name. */
         cmdline,     /* Command line. */
         NULL,     /* Process handle not inheritable. */
         NULL,     /* Thread handle not inheritable. */
         TRUE,     /* yes, inherit handles. */
         DETACHED_PROCESS, /* No console for you. */
         NULL,     /* Use parent's environment block. */
         NULL,     /* Use parent's starting directory. */
         &si,     /* Pointer to STARTUPINFO structure. */
         &pi);     /* Pointer to PROCESS_INFORMATION structure. */
 
    if (!ok) {
     DWORD err = GetLastError();
     int chars = _snprintf(msg, sizeof(msg) - 1,
         "Tried to launch: /"%s/", but got error [%u]: ", cmdline, err);
 
     FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS|
         FORMAT_MESSAGE_MAX_WIDTH_MASK, 0L, err, 0, &msg[chars],
         (300-chars), 0);
     WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, lstrlen(msg), &err,NULL);
     return 2;
    }
 
    /*
     * Close our references to the write handles that have now been inherited.
     */
 
    CloseHandle(si.hStdOutput);
    CloseHandle(si.hStdError);
 
    WaitForInputIdle(pi.hProcess, 5000);
    CloseHandle(pi.hThread);
 
    /*
     * Start the pipe reader threads.
     */
 
    pipeThreads[0] = CreateThread(NULL, 0, ReadFromPipe, &Out, 0, &threadID);
    pipeThreads[1] = CreateThread(NULL, 0, ReadFromPipe, &Err, 0, &threadID);
 
    /*
     * Block waiting for the process to end.
     */
 
    WaitForSingleObject(pi.hProcess, INFINITE);
    CloseHandle(pi.hProcess);
 
    /*
     * Wait for our pipe to get done reading, should it be a little slow.
     */
 
    WaitForMultipleObjects(2, pipeThreads, TRUE, INFINITE);
    CloseHandle(pipeThreads[0]);
    CloseHandle(pipeThreads[1]);
 
    return 0;
}
纏ar DWORD WINAPI
ReadFromPipe(
    LPVOID args)
{
     pipeinfo *pi = (pipeinfo *) args;
     char *lastBuf = pi->buffer;
     DWORD dwRead;
     BOOL ok;
     char buf[2000];
 
again:
     ok = ReadFile(pi->pipe, buf, 2000, &dwRead, 0L);
     if (!ok || dwRead == 0)
     {
         CloseHandle(pi->pipe);
         return 0;
     }
     else
     {
         buf[dwRead] = 0;
         printf("%s", buf);
     }
     goto again;
 
     return 0; /* makes the compiler happy */
}
 

你可能感兴趣的:(调用一个控制台程序并取得其输出)