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

892 阅读2分钟

Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情

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;
 }