windows下C与C++执行cmd命令并实时获取输出

举报
DS小龙哥 发表于 2022/02/22 16:52:04 2022/02/22
【摘要】 在windows下一般会使用系统的cmd命令或者其他现成的一些命令行可执行程序来完成一些操作,比如:调用ping命令来测试网络是否畅通、调用ffmpeg命令进行视频转码等等。为了能在软件界面上有更好的交互输出,都需要将命令执行的过程拿到,进行处理,然后在界面上进行显示,让用户知道程序正在正常运行,下面就介绍几种输出的获取方式。

1. 前言

在windows下一般会使用系统的cmd命令或者其他现成的一些命令行可执行程序来完成一些操作,比如:调用ping命令来测试网络是否畅通、调用ffmpeg命令进行视频转码等等。为了能在软件界面上有更好的交互输出,都需要将命令执行的过程拿到,进行处理,然后在界面上进行显示,让用户知道程序正在正常运行,下面就介绍几种输出的获取方式。

当前开发环境: win10 64位 IDE-MSVC2017

2. 使用_popen执行进程

通过_popen打开进程进行执行,通过fgets获取进程的输出。

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

int run_cmd(const char * cmd)
{
	char MsgBuff[1024];
	int MsgLen=1020;
	FILE * fp;
	if (cmd == NULL)
	{
		return -1;
	}
	if ((fp = _popen(cmd, "r")) == NULL)
	{
		return -2;
	}
	else
	{
		memset(MsgBuff, 0, MsgLen);

		//读取命令执行过程中的输出
		while (fgets(MsgBuff, MsgLen, fp) != NULL)
		{
			printf("MsgBuff: %s\n", MsgBuff);
		}

		//关闭执行的进程
		if(_pclose(fp) == -1)
		{
			return -3;
		}
	}
	return 0;
}

int main()
{
	//const char *cmd = "ffmpeg -i D:\\123.mp4 -vf reverse D:\\out\\out1.mp4";
	
	const char *cmd = "ping www.baidu.com";
	int ret = 0;
	ret = run_cmd(cmd);
	printf("命令执行结果:%d\r\n",ret);

	getchar();
	return 0;
}

image-20220222151051424

3. CreateProcess重定向输出到文件

下面使用CreateProcess调用子进程运行,将输出保存在文件中,阻塞等待进程执行完毕。

int my_CreateProcess()
{
	SECURITY_ATTRIBUTES sa;
	sa.nLength = sizeof(sa);
	sa.lpSecurityDescriptor = NULL;
	sa.bInheritHandle = TRUE;

	_unlink("D:/out/output.log");

	HANDLE h = CreateFile((L"D:/out/output.log"),
		FILE_APPEND_DATA,
		FILE_SHARE_WRITE | FILE_SHARE_READ,
		&sa,
		OPEN_ALWAYS,
		FILE_ATTRIBUTE_NORMAL,
		NULL);

	PROCESS_INFORMATION pi;
	STARTUPINFO si;
	BOOL ret = FALSE;
	DWORD flags = CREATE_NO_WINDOW;

	ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
	ZeroMemory(&si, sizeof(STARTUPINFO));
	si.cb = sizeof(STARTUPINFO);
	si.dwFlags |= STARTF_USESTDHANDLES;
	si.hStdInput = NULL;
	si.hStdError = h;
	si.hStdOutput = h;

	TCHAR cmd[] = TEXT("ping www.baidu.com");
	ret = CreateProcess(NULL, cmd, NULL, NULL, TRUE, flags, NULL, NULL, &si, &pi);

	if (ret)
	{
		WaitForSingleObject(pi.hProcess, INFINITE);
		printf("执行成功....\n");
		CloseHandle(pi.hProcess);
		CloseHandle(pi.hThread);
		//关闭文件
		CloseHandle(h);
		return 0;
	}
	//关闭文件
	CloseHandle(h);
	printf("执行失败....\n");
	return -1;
}

image-20220221172750651

4. CreateProcess重定向输出到管道

为了能实时获取CreateProcess打开进程运行时实时输出的结果,可以将CreateProcess的输出重定向到管道文件,CreateProcess将数据写到管道的写端,在父进程里再从管道的读端就能实时读取数据。

int my_CreateProcess()
{
	BOOL run_pipe;

	PROCESS_INFORMATION pi;
	STARTUPINFO si;
	BOOL ret = FALSE;
	DWORD flags = CREATE_NO_WINDOW;

	_unlink("D:/out/output.log");

	char pBuffer[210];
	SECURITY_ATTRIBUTES sa;
	sa.nLength = sizeof(SECURITY_ATTRIBUTES);
	sa.lpSecurityDescriptor = NULL;
	sa.bInheritHandle = TRUE;
	HANDLE hReadPipe, hWritePipe;
	run_pipe=CreatePipe(&hReadPipe, &hWritePipe, &sa, 0);
	printf("run_pipe=%d\n", run_pipe);

	ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
	ZeroMemory(&si, sizeof(STARTUPINFO));
	si.cb = sizeof(STARTUPINFO);
	si.dwFlags |= STARTF_USESTDHANDLES; 
	si.hStdInput = NULL;
	si.hStdError = hWritePipe;
	si.hStdOutput = hWritePipe;

	TCHAR cmd[] = TEXT("ffmpeg -i D:\\123.mp4 -vf reverse D:\\out\\out1.mp4");

	ret = CreateProcess(NULL, cmd, NULL, NULL, TRUE, flags, NULL, NULL, &si, &pi);

	if (ret)
	{
		while (true)
		{
			DWORD ExitCode = 0;
			//判断进程是否执行结束
			GetExitCodeProcess(pi.hProcess, &ExitCode);
			if (ExitCode == STILL_ACTIVE) //正在运行
			{
				DWORD RSize=0;
				BOOL run_s=0;
				run_s =ReadFile(hReadPipe, pBuffer,200,&RSize,NULL);
				pBuffer[RSize] = '\0';
				printf("返回结果:%d,%d,%s\n", run_s, RSize, pBuffer);
			}
			else //结束
			{
				printf("执行完毕...\n");
				break;
			}
		}
		
		//WaitForSingleObject(pi.hProcess, INFINITE);
		printf("执行成功....\n");
		CloseHandle(pi.hProcess);
		CloseHandle(pi.hThread);
		return 0;
	}
	printf("执行失败....\n");
	return -1;
}
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。