使用匿名管道和CreateProcess隐式调用控制台程序

2021/5/12 CC++通信Windows

# 1 前言

近期工作内容需要在一个程序中包装一个控制台程序,用于执行cmd命令获取结果,经过对Windows平台进程和管道通信的学习后,采用 匿名管道 和 CreateProcess 隐式调用控制台程序来实现这个需求。

# 2 核心内容

Windows平台进程创建和退出 记录了 CreateProcess 的基本用法。

管道通信:匿名管道) 记录了匿名管道的定义及其基本用法。

本文使用匿名管道和CreateProcess隐式调用控制台程序,核心内容为在程序中利用 CreateProcess 创建 控制台子进程,并利用管道技术重定向控制台子程序与主进程间的标准输入输出,从而达到在程序中封装控制台的目的,用于在程序运行中执行cmd命令,并获取其结果,希望对自己与各位有所帮助。

# 3 示例代码

#include <stdio.h>
#include <string.h>
#include <windows.h>

int main() {
	SECURITY_ATTRIBUTES sa = { 0 };
	STARTUPINFO         si = { 0 };
	PROCESS_INFORMATION pi = { 0 };
	HANDLE              hPipeOutputRead = NULL;
	HANDLE              hPipeOutputWrite = NULL;
	HANDLE              hPipeInputRead = NULL;
	HANDLE              hPipeInputWrite = NULL;
	BOOL                bTest = 0;
	DWORD               dwNumberOfBytesRead = 0;
	DWORD               dwNumberOfBytesWrite = 0;
	CHAR                szMsg[1024];
	CHAR                szBuffer[1024 * 4];

	sa.nLength = sizeof(sa);
	sa.bInheritHandle = TRUE;
	sa.lpSecurityDescriptor = NULL;

	CreatePipe(&hPipeOutputRead, &hPipeOutputWrite, &sa, 0); //创建标准输出管道
	CreatePipe(&hPipeInputRead, &hPipeInputWrite, &sa, 0);   //创建标准输入管道

	// 创建控制台子进程,进行输入输出重定向,并隐藏其窗口
	si.cb = sizeof(si);
	si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
	si.wShowWindow = SW_HIDE;
	si.hStdInput = hPipeInputRead;
	si.hStdOutput = hPipeOutputWrite;
	si.hStdError = hPipeOutputWrite;

	CreateProcess(NULL, "cmd.exe", NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi);

	// 关闭输出管道的写句柄和输入管道的读句柄
	CloseHandle(hPipeOutputWrite);
	CloseHandle(hPipeInputRead);

	// 向输入管道写入cmd命令,即执行命令
	sprintf(szMsg, "systeminfo\nexit\n");
	WriteFile(hPipeInputWrite, &szMsg, strlen(szMsg), &dwNumberOfBytesWrite, NULL);

	while (TRUE) {
		bTest = ReadFile(hPipeOutputRead, &szBuffer, sizeof(szBuffer), &dwNumberOfBytesRead, NULL);
		if (!bTest) {
			sprintf(szMsg, "Error #%d reading pipe.", GetLastError());
			MessageBox(NULL, szMsg, "WinPipe", MB_OK);
			break;
		}
		szBuffer[dwNumberOfBytesRead] = 0;  // 结尾处添加'\0'
		MessageBox(NULL, szBuffer, "WinPipe", MB_OK);
	}

	WaitForSingleObject(pi.hProcess, INFINITE); // 等待子进程结束 

	// 关闭相关句柄
	CloseHandle(pi.hThread);
	CloseHandle(pi.hProcess);
	CloseHandle(hPipeOutputRead);
	CloseHandle(hPipeInputWrite);

	return 0;
}