您的位置:首页 > 其它

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

2007-10-19 14:59 555 查看
在程序设计中,有时候需要调用一些控制台程序并取得其在控制台上的输出,如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 */
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐