首页
社区
课程
招聘
[原创]Windows C/C++ Win32 管道读取cmd命令行执行输出结果
发表于: 2023-3-17 14:48 11332

[原创]Windows C/C++ Win32 管道读取cmd命令行执行输出结果

2023-3-17 14:48
11332

一、背景

最近在一个Windows客户端程序,要求用Win32 x86来开发,其中一个功能在调用各种Windows的API来实现后发现效果不是很好,而且代码冗余

 

转换思路后,改用CMD命令来解决需求,效果好了很多,但其中比较头疼的一个问题是读取CMD命令的执行结果,而且程序是要求管理员权限运行的,首先想到的是利用CreatePipe、CreateProcessA、ReadFile这一堆API来实现,但网上各种找文章查资料后,自己编码,效果始终不理想,要么子进程父进程的权限问题,要么堆出现问题,或者线程阻塞,要知道这是个大型项目,调试很头疼,一直在解决Bug,困在这好长一段时间。

 

后面偶然发现Windows开发中的_popen函数,瞬间解决了这个问题

 

至于密码过程和思路就不详细展开了,有个需求的也不要赘述,直接看源码吧。
算是做个笔记或者提供点思路吧。

二、源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#include <stdio.h>
#include <stdlib.h>
 
#include <iostream>
#include <string>
 
std::string ExecuteCommandLine(std::string cmd);
 
std::string ExecuteCommandLine(std::string cmd)
{
 
    std::string cmd_result = std::string();
 
    char psBuffer[0x2000] = { 0 };
    FILE* pPipe;
 
    /* Run DIR so that it writes its output to a pipe. Open this
     * pipe with read text attribute so that we can read it
     * like a text file.
     */
 
    if ((pPipe = _popen(cmd.c_str(), "rt")) == NULL)
    {
        exit(1);
    }
 
    /* Read pipe until end of file, or an error occurs. */
 
    while (fgets(psBuffer, 0x2000, pPipe))
    {
        cmd_result += psBuffer;
        memset(psBuffer, 0, 0x2000);
    }
 
    int endOfFileVal = feof(pPipe);
    int closeReturnVal = _pclose(pPipe);
 
    if (endOfFileVal)
    {
        printf("\nProcess returned %d\n", closeReturnVal);
    }
    else
    {
        printf("Error: Failed to read the pipe to the end.\n");
    }
 
    return cmd_result;
}
 
 
int main()
{
    std::string exec_result = ExecuteCommandLine("whoami /priv");
 
 
    std::cout << exec_result << std::endl;
 
    return 0;
}

参考资料

1、 MSDN _popen

 

2、CreatePipe


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 0
支持
分享
最新回复 (9)
雪    币: 15973
活跃值: (4177)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2

命令获取一些参数很实用

最后于 2023-3-17 15:59 被SnowRen编辑 ,原因:
2023-3-17 15:22
0
雪    币: 7527
活跃值: (3120)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
最近写的linux程序用的就是popen
2023-3-17 16:03
0
雪    币: 117
活跃值: (3047)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
這把戲,可以參考 https://github.com/terrylao/WinCat
2023-3-17 16:52
0
雪    币: 515
活跃值: (3272)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
wem
5
good
2023-4-12 18:16
0
雪    币: 2296
活跃值: (6668)
能力值: ( LV7,RANK:102 )
在线值:
发帖
回帖
粉丝
6
说白了就是缺少一些基础的库,C++这玩意确实就是这样子的
2023-4-14 11:21
0
雪    币: 203
活跃值: (1144)
能力值: ( LV9,RANK:195 )
在线值:
发帖
回帖
粉丝
7
C++开发大型项目,维护愁死人
2023-4-14 16:17
0
雪    币: 4390
活跃值: (4378)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
std::string ExecuteCommandLine(std::string cmd)
{

	std::string cmd_result = std::string();

	HANDLE hReadPipe, hWritePipe;
	SECURITY_ATTRIBUTES saAttr;
	saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
	saAttr.bInheritHandle = TRUE;
	saAttr.lpSecurityDescriptor = NULL;

	if (!CreatePipe(&hReadPipe, &hWritePipe, &saAttr, 0))
	{
		exit(1);
	}

	STARTUPINFOA si;
	PROCESS_INFORMATION pi;
	ZeroMemory(&si, sizeof(si));
	si.cb = sizeof(si);

	si.hStdError = hWritePipe;
	si.hStdOutput = hWritePipe;
	si.dwFlags = STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;
	si.wShowWindow = SW_HIDE;
	if (!CreateProcessA(NULL, (LPSTR)cmd.c_str(), NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi))
	{
		exit(1);
	}

	CloseHandle(hWritePipe);

	char psBuffer[0x2000] = { 0 };
	DWORD dwRead;
	BOOL bSuccess = FALSE;

	while (bSuccess = ReadFile(hReadPipe, psBuffer, sizeof(psBuffer), &dwRead, NULL))
	{
		if (dwRead == 0)
		{
			break;
		}
		cmd_result += psBuffer;
		memset(psBuffer, 0, 0x2000);
	}

	int closeReturnVal = 0;
	if (GetExitCodeProcess(pi.hProcess, (LPDWORD)&closeReturnVal))
	{
		printf("\nProcess returned %d\n", closeReturnVal);
	}
	else
	{
		printf("Error: Failed to read the pipe to the end.\n");
	}

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

	return cmd_result;
}



API也简单.

2023-4-14 22:22
0
雪    币: 3680
活跃值: (3086)
能力值: ( LV8,RANK:147 )
在线值:
发帖
回帖
粉丝
9
_popen也不太好,我最近遇到一个问题,win32 GUI程序,使用_popen无法隐藏命令行,最后还是老老实实用API管道搞的
2023-4-25 11:20
0
雪    币: 261
活跃值: (547)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
10
Boost.Process
2023-9-26 17:09
0
游客
登录 | 注册 方可回帖
返回
//