Loading [MathJax]/jax/input/TeX/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >在Windows平台上使用C++执行外部命令的两种方法

在Windows平台上使用C++执行外部命令的两种方法

原创
作者头像
Power
发布于 2025-04-03 08:18:06
发布于 2025-04-03 08:18:06
13300
代码可运行
举报
运行总次数:0
代码可运行

在本文中,我将向大家介绍如何在Windows平台上使用C++执行外部命令。我们将探讨两种不同的方法,并对它们进行比较和描述。当我们需要在程序中集成其他应用程序或运行脚本时,这两种方法都非常有用。

在详细讲解这两种方法之前,让我们先了解为什么我们需要在C++程序中执行外部命令。有时,我们需要与其他进程进行交互,例如运行一个脚本、启动一个新进程或收集系统信息。在这些情况下,执行外部命令可以帮助我们轻松地完成这些任务。

现在让我们开始深入了解这两种方法。

方法 1:使用_popen和_pclose函数

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 代码片段1(Method 1)
#include <array>
#include <cstdio>
#include <fstream>
#include <iostream>

std::string exec(const char *cmd) {
  std::array<char, 128> buffer;
  std::string result;
  FILE *pipe = _popen(cmd, "r");

  if (!pipe) {
    throw std::runtime_error("_popen() failed!");
  }

  while (fgets(buffer.data(), buffer.size(), pipe) != nullptr) {
    result += buffer.data();
  }

  int exitStatus = _pclose(pipe);
  if (exitStatus != 0) {
    throw std::runtime_error("Command exited with non-zero status.");
  }

  return result;
}

int main() {
  try {
    // Replace "command" with your command
    std::string aniCommand = "command";
    std::string output = exec(aniCommand.c_str());

    // Save output to file
    std::ofstream outputFile("output.txt");
    if (outputFile.is_open()) {
      outputFile << output;
      outputFile.close();
      std::cout << "Output saved to file." << std::endl;
    } else {
      std::cout << "Error opening file." << std::endl;
    }
  } catch (const std::runtime_error &e) {
    std::cerr << "Error: " << e.what() << std::endl;
  }

  return 0;
}

该方法主要利用了Microsoft提供的_popen_pclose扩展函数。该方法相对简单且易于理解。首先,我们使用_popen创建一个管道并与子进程关联;接着,我们读取子进程通过管道发送的输出。然后,我们关闭管道并检查子进程的退出状态。最后,我们将从子进程获取的输出保存到文件中。

优点

  1. 使用_popen和_pclose函数执行外部命令,较简单易懂。
  2. 将命令输出保存到文件中。

缺点

  1. 可能会遇到兼容性问题,因为_popen和_pclose是Microsoft扩展函数,可能不同编译器的支持程度有所差异。

方法 2:使用Windows API

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 代码片段2(Method 2)
#include <iostream>
#include <stdexcept>
#include <string>
#include <vector>
#include <windows.h>

std::string exec(const char *cmd) {
  SECURITY_ATTRIBUTES sa;
  sa.nLength = sizeof(sa);
  sa.lpSecurityDescriptor = NULL;
  sa.bInheritHandle = TRUE;

  HANDLE hRead, hWrite;

  if (!CreatePipe(&hRead, &hWrite, &sa, 0)) {
    throw std::runtime_error("CreatePipe failed");
  }

  STARTUPINFO si;
  ZeroMemory(&si, sizeof(si));
  si.cb = sizeof(si);
  si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
  si.hStdOutput = hWrite;
  si.hStdError = hWrite;

  PROCESS_INFORMATION pi;
  ZeroMemory(&pi, sizeof(pi));

  if (!CreateProcess(NULL, (LPSTR)cmd, NULL, NULL, TRUE, 0, NULL, NULL, &si,
                     &pi)) {
    CloseHandle(hWrite);
    CloseHandle(hRead);
    throw std::runtime_error("CreateProcess failed");
  }

  CloseHandle(hWrite);

  std::vector<char> buffer(4096);
  DWORD bytesRead;
  std::string output;

  while (true) {
    if (!ReadFile(hRead, buffer.data(), buffer.size(), &bytesRead, NULL)) {
      break;
    }
    output.append(buffer.cbegin(), buffer.cbegin() + bytesRead);
  }

  CloseHandle(hRead);
  CloseHandle(pi.hProcess);
  CloseHandle(pi.hThread);

  return output;
}

int main() {
  // Ensure your command generates ANSI color codes
  std::string output = exec("d:\\Project\\cpp-practice\\build\\cpp-practice."
                            "exe --gtest_color=yes 2>&1");
  std::cout << output;
  return 0;
}

与方法 1 相比,该方法提供了更多底层控制。这里,我们使用Windows APICreatePipeCreateProcessReadFile)来执行外部命令。首先,我们创建一个匿名管道;接着,我们创建一个新进程并将管道与其关联。然后,我们读取子进程通过管道发送的输出。最后,关闭管道以及相关进程和线程句柄。

优点

  1. 使用Windows API(CreatePipe、CreateProcess和ReadFile)来执行外部命令,更通用且适配多种编译器。
  2. 可以获取子进程stdout和stderr的输出。

缺点

  1. 代码相对复杂,需要处理更多底层Windows API细节。
  2. 没有将命令输出保存到文件中。

结论

在选择使用哪种方法时,应根据具体需求和目标进行权衡。如果你只需执行简单外部命令并保存输出结果到文件,那么方法 1 可能更适合你。然而,如果你需要控制更多底层细节或确保与不同编译器的兼容性,方法 2 可能是更好的选择。

两种方法均有其优点和局限性;最佳策略取决于你的具体需求和项目情况。希望本文能为你在Windows平台上使用C++执行外部命令提供帮助。在未来的编程实践中,你可以灵活地运用这些方法以达到预期目标。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
CreatePipe、CreateProcess函数
管 道(Pipe)实际是用于进程间通信的一段共享内存,创建管道的进程称为管道服务器,连接到一个管道的进程为管道客户机。一个进程在向管道写入数据后,另 一进程就可以从管道的另一端将其读取出来。匿名管道(Anonymous Pipes)是在父进程和子进程间单向传输数据的一种未命名的管道,只能在本地计算机中使用,而不可用于网络间的通信。
全栈程序员站长
2022/09/17
1.4K0
C/C++/Delphi 调用命令并且显示执行结果
* 网站名称:obaby@mars * 网址:https://h4ck.org.cn/ * 本文标题: 《C/C++/Delphi 调用命令并且显示执行结果》 * 本文链接:https://h4ck.org.cn/2011/11/cdelphi-execute-cmd-commands-and-get-result/ * 转载文章请标明文章来源,原文标题以及原文链接。请遵从 《署名-非商业性使用-相同方式共享 2.5 中国大陆 (CC BY-NC-SA 2.5 CN) 》许可协议。
obaby
2023/02/24
7810
windows下C与C++执行cmd命令并实时获取输出
在windows下一般会使用系统的cmd命令或者其他现成的一些命令行可执行程序来完成一些操作,比如:调用ping命令来测试网络是否畅通、调用ffmpeg命令进行视频转码等等。为了能在软件界面上有更好的交互输出,都需要将命令执行的过程拿到,进行处理,然后在界面上进行显示,让用户知道程序正在正常运行,下面就介绍几种输出的获取方式。
DS小龙哥
2022/05/28
7.2K0
windows下C与C++执行cmd命令并实时获取输出
C/C++ 匿名管道反弹CMDShell
下载NC https://eternallybored.org/misc/netcat/
王 瑞
2022/12/28
6250
17.1 隐藏执行CMD命令
本章内容涉及使用Socket API和CMD命令行工具实现本地CMD命令执行、无管道正向CMD和无管道反向CMD三种功能。执行本地CMD实现使用CreateProcess函数创建一个新的CMD进程,并将标准输入、输出和错误输出重定向到当前进程的标准输入、输出和错误输出。无管道正向CMD和无管道反向CMD使用WSASocket函数创建TCP套接字,并将CMD进程的标准输入、输出和错误输出重定向到套接字的句柄上,通过网络连接实现远程命令执行功能。
王 瑞
2023/10/22
5320
17.1 隐藏执行CMD命令
如何在父进程中读取子(外部)进程的标准输出和标准错误输出结果
        最近接手一个小项目,要求使用谷歌的aapt.exe获取apk软件包中的信息。依稀记得去年年中时,有个同事也问过我如何获取被调用进程的输出结果,当时还研究了一番,只是没有做整理。今天花点时间,将该方法整理成文。(转载请指明出于breaksoftware的csdn博客)
方亮
2019/01/16
4.7K0
CreatePipe匿名管道通信
大家好,又见面了,我是你们的朋友全栈君。 管道(Pipe)实际是用于进程间通信的一段共享内存,创建管道的进程称为管道服务器,连接到一个管道的进程为管道客户机。一个进程在向管道写入数据后,另一进程就可以从管道的另一端将其读取出来。匿名管道(Anonymous Pipes)是在父进程和子进程间单向传输数据的一种未命名的管道,只能在本地计算机中使用,而不可用于网络间的通信。     匿名管道实施细则     匿名管道由CreatePipe()函数创建,该函数在创建匿名管道的同时返回两个句柄:管道读句柄和管道写句柄。CreatePipe()的函数原型为:   BOOL CreatePipe(PHANDLE hReadPipe, // 指向读句柄的指针    PHANDLE hWritePipe, // 指向写句柄的指针    LPSECURITY_ATTRIBUTES lpPipeAttributes, // 指向安全属性的指针    DWORD nSize // 管道大小   );     通过hReadPipe和hWritePipe所指向的句柄可分别以只读、只写的方式去访问管道。在使用匿名管道通信时,服务器进程必须将其中的一个句柄传送给客户机进程。句柄的传递多通过继承来完成,服务器进程也允许这些句柄为子进程所继承。除此之外,进程也可以通过诸如DDE或共享内存等形式的进程间通信将句柄发送给与其不相关联的进程。     在调用CreatePipe()函数时,如果管道服务器将lpPipeAttributes 指向的SECURITY_ATTRIBUTES数据结构的数据成员bInheritHandle设置为TRUE,那么CreatePipe()创建的管道读、写句柄将会被继承。管道服务器可调用DuplicateHandle()函数改变管道句柄的继承。管道服务器可以为一个可继承的管道句柄创建一个不可继承的副本或是为一个不可继承的管道句柄创建一个可继承的副本。CreateProcess()函数还可以使管道服务器有能力决定子进程对其可继承句柄是全部继承还是不继承。     在生成子进程之前,父进程首先调用Win32 API SetStdHandle()使子进程、父进程可共用标准输入、标准输出和标准错误句柄。当父进程向子进程发送数据时,用SetStdHandle()将管道的读句柄赋予标准输入句柄;在从子进程接收数据时,则用SetStdHandle()将管道的写句柄赋予标准输出(或标准错误)句柄。然后,父进程可以调用进程创建函数CreateProcess()生成子进程。如果父进程要发送数据到子进程,父进程可调用WriteFile()将数据写入到管道(传递管道写句柄给函数),子进程则调用GetStdHandle()取得管道的读句柄,将该句柄传入ReadFile()后从管道读取数据。     如果是父进程从子进程读取数据,那么由子进程调用GetStdHandle()取得管道的写入句柄,并调用WriteFile()将数据写入到管道。然后,父进程调用ReadFile()从管道读取出数据(传递管道读句柄给函数)。     在用WriteFile()函数向管道写入数据时,只有在向管道写完指定字节的数据后或是在有错误发生时函数才会返回。如管道缓冲已满而数据还没有写完,WriteFile()将要等到另一进程对管道中数据读取以释放出更多可用空间后才能够返回。管道服务器在调用CreatePipe()创建管道时以参数nSize对管道的缓冲大小作了设定。     匿名管道并不支持异步读、写操作,这也就意味着不能在匿名管道中使用ReadFileEx()和WriteFileEx(),而且ReadFile()和WriteFile()中的lpOverLapped参数也将被忽略。匿名管道将在读、写句柄都被关闭后退出,也可以在进程中调用CloseHandle()函数来关闭此句柄   /   匿名管道程序示例     总的来说,匿名管道程序是比较简单的。在下面将要给出的程序示例中,将由父进程(管道服务器)创建一个子进程(管道客户机),子进程回见个其全部的标准输出发送到匿名管道中,父进程再从管道读取数据,一直到子进程关闭管道的写句柄。其中,匿名管道服务器程序的实现清单如下:   STARTUPINFO si;   PROCESS_INFORMATION pi;   char ReadBuf[100];   DWORD ReadNum;   HANDLE hRead; // 管道读句柄   HANDLE hWrite; // 管道写句柄   BOOL bRet = CreatePipe(&hRead, &hWrite, NULL, 0); // 创建匿名管道   if (bRet
全栈程序员站长
2022/09/17
1.1K0
WindowsAPI 之 CreatePipe、CreateProcess[通俗易懂]
A pipe is a section of shared memory that processes use for communication. The process that creates a pipe is the pipe server. A process that connects to a pipe is a pipe client. One process writes information to the pipe, then the other process reads the information from the pipe. This overview describes how to create, manage, and use pipes.
全栈程序员站长
2022/09/06
4.4K0
WindowsAPI 之 CreatePipe、CreateProcess[通俗易懂]
如何使用使用 C++ 获得 shell 命令后的输出
如果是在 Windows 上,用 _popen 和 _pclose 代替 popen 和 pclose 即可。
ClearSeve
2022/02/10
2.7K0
如何在应用程序中调用CMD并返回运行结果
要求做一个图形界面的应用程序,输入命令行的命令,在后台调用CMD程序执行该命令但不显示DOS命令行窗口,而且能实时显示运行的结果。哪位知道怎么处理?谢啦
用户3519280
2023/07/06
6870
ffmpeg mp4解码管道输出的问题
上面主进程读取的字节数如下:共,2834行,与理想的166帧166行相差甚远,每帧560*320*3=537600也和下面的不一样。
shirishiyue
2020/10/13
2.2K0
windows下C语言使用curl库访问HTTP下载文件
cURL是一个利用URL语法在命令行下工作的文件传输工具,1997年首次发行。它支持文件上传和下载,所以是综合传输工具,但按传统,习惯称cURL为下载工具。cURL还包含了用于程序开发的libcurl。
DS小龙哥
2022/06/21
2.7K0
windows下C语言使用curl库访问HTTP下载文件
windows 多任务与进程
多任务的本质就是并行计算,它能够利用至少2处理器相互协调,同时计算同一个任务的不同部分,从而提高求解速度,或者求解单机无法求解的大规模问题。以前的分布式计算正是利用这点,将大规模问题分解为几个互不不相关的问题,将这些计算问题交给局域网中的其他机器计算完成,然后再汇总到某台机器上,显示结果,这样就充分利用局域网中的计算机资源。 相对的,处理完一步接着再处理另外一步,将这样的传统计算模式称为串行计算。 在提高处理器的相关性能主要有两种方式,一种是提高单个处理器处理数据的速度,这个主要表现在CPU主频的调高上,而当前硬件总有一个上限,以后再很难突破,所以现在的CPU主要采用的是调高CPU的核数,这样CPU的每个处理器都处理一定的数据,总体上也能带来性能的提升。 在某些单核CPU上Windows虽然也提供了多任务,但是这个多任务是分时多任务,也就是每个任务只在CPU中执行一个固定的时间片,然后再切换到另一个任务,由于每个任务的时间片很短,所以给人的感觉是在同一时间运行了多个任务。单核CPU由于需要来回的在对应的任务之间切换,需要事先保存当前任务的运行环境,然后通过轮循算法找到下一个运行的任务,再将CPU中寄存器环境改成新任务的环境,新任务运行到达一定时间,又需要重复上述的步骤,所以在单核CPU上使用多任务并不能带来性能的提升,反而会由在任务之间来回切换,浪费宝贵的资源,多任务真正使用场合是多核的CPU上。 windows上多任务的载体是进程和线程,在windows中进程是不执行代码的,它只是一个载体,负责从操作系统内核中分配资源,比如每个进程都有4GB的独立的虚拟地址空间,有各自的内核对象句柄等等。线程是资源分配的最小单元,真正在使用这些资源的是线程。每个程序都至少有一个主线程。线程是可以被执行的最小的调度单位。
Masimaro
2018/08/31
1.2K0
C/C 中一次性执行多个DOS命令的实现思路
最近给公司的一个系统写了个启动的脚本,但是领导说批处理这样的脚本太low了,要使用EXE来启动,未来还要使用加密工具对EXE进行加密。
用户3519280
2023/07/06
2890
进程间通信之CreatePipe
BOOL WINAPI CreatePipe( _Out_ PHANDLE hReadPipe, _Out_ PHANDLE hWritePipe, _In_opt_ LPSECURITY_ATTRIBUTES lpPipeAttributes, _In_ DWORD nSize );
全栈程序员站长
2022/09/17
1K0
c++ 网络编程(三)TCP/IP LINUX/windows 进程间的通信原理与实现代码 基于多进程的服务端实现
原文链接:https://www.cnblogs.com/DOMLX/p/9613027.html
徐飞机
2018/09/30
1.4K0
c++ 网络编程(三)TCP/IP  LINUX/windows  进程间的通信原理与实现代码  基于多进程的服务端实现
Windows 编程(多进程)
进程从来不执行任何东西,它只是纯种的容器,若要使进行完成某项操作,它必 须拥有一个在它的环境中运行的纯种,此线程负责执行包含在进程的地址空 间的中的代码.也就是,真正完成代码执行的是线程,而进程只是纯种的容器, 或者说是线程的执行环境.
全栈程序员站长
2022/07/13
1.2K0
进程的创建与使用(win32-API)
进程可以被视作操作系统中运行程序的一个实例,是系统资源分配和调度的基本单位。每一个进程都拥有自己独立的地址空间、一组状态信息(如打开的文件、内存映射等),以及一个或多个线程来执行代码。进程之间的隔离性确保了它们不会相互干扰,而这种隔离性也是多任务操作系统能够同时运行多个应用程序而不发生冲突的关键。
DS小龙哥
2025/05/27
1200
进程的创建与使用(win32-API)
C/C++ 获取 MAC 地址的几种方法
Netbios #include <windows.h> #pragma comment(lib, "Netapi32.lib") namespace { bool GetAdapterInfo(int adapterNum, std::string& macOUT) { NCB Ncb; memset(&Ncb, 0, sizeof(Ncb)); Ncb.ncb_command = NCBRESET; // 重置网卡,以便我们可以查询 Ncb.ncb_lana_num = adapterNum
王 瑞
2022/12/28
1.5K0
Windows进程通信之一看就懂的匿名管道通信
匿名管道是用来父进程跟子进程通信的.还有一种是命名管道.不需要父子进程就可以进行通信的.今天先说匿名管道的. 匿名管道. 就是父进程创建子进程. 读取子进程数据.或者给子进程发送数据.当然子进程也可以给父进程发送数据.以及读取父进程发送过来的数据.
IBinary
2019/06/11
2.2K0
Windows进程通信之一看就懂的匿名管道通信
相关推荐
CreatePipe、CreateProcess函数
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验