天天看点

Windows管道技术

关于Windows管道技术:

API函数(主要):

CreatePipe()用于创建管道

ReadFile() 用于读管道

WriteFile()用于写管道

变量类型(主要):

HANDLE

Windows管道技术

然后直接上代码

注意:这里我是用管道读取CMD的数据用CreateProcess()函数创建的进程用TerminateProcess()终止进程

用下面的结构体的几个成员指定输入输出流的流向

s_info.hStdError = hwcmd;

s_info.hStdInput = hrcmd;

s_info.hStdOutput = hwcmd;>

// win_pipe.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include "pch.h"
#include <iostream>
#include <stdio.h>
#include <windows.h>
#include <string>
#include <tchar.h>

constexpr auto SEND_BUFF_SIZE = 1024;

using namespace std;

inline void winerr(void);		//用于打印windows错误代码

int main()
{
	HANDLE hrcmd = NULL;
	HANDLE hwcmd = NULL;
	HANDLE hrexe = NULL;
	HANDLE hwexe = NULL;
	HANDLE hpro = NULL;

	SECURITY_ATTRIBUTES sa;		//Windows安全设置:此结构为各种函数创建的对象提供安全设置
	PROCESS_INFORMATION pro_info;

	sa.nLength = sizeof(SECURITY_ATTRIBUTES);
	sa.lpSecurityDescriptor = NULL;
	sa.bInheritHandle = true;

	if (!CreatePipe(&hrexe, &hwcmd, &sa, 0))
	{
		winerr();
		return 1;
	}
	else
	{
		cout << "creat pipe1 noerror" << endl;
	}
	if (!CreatePipe(&hrcmd, &hwexe, &sa, 0))
	{
		winerr();
		return 1;
	}
	else
	{
		cout << "creat pipe2 noerror" << endl;
	}

	//启动信息

	STARTUPINFO s_info;		//指定创建时进程的窗口工作站,桌面,标准句柄和主窗口的外观
	GetStartupInfo(&s_info);
	s_info.cb = sizeof(STARTUPINFO);
	s_info.lpReserved = NULL;
	s_info.wShowWindow = SW_HIDE;
	s_info.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
	s_info.hStdError = hwcmd;
	s_info.hStdInput = hrcmd;
	s_info.hStdOutput = hwcmd;

	cout << "初始化完成" << endl;

	WCHAR cmdpath[1024] = _T("\n");
	GetSystemDirectory(cmdpath, sizeof(cmdpath));
	wcsncat_s(cmdpath, _T("\\cmd.exe"), 9);	//宽字符串连接。。

	wcout << "path:" << cmdpath << endl;

		//创建cmd进程
	if (!CreateProcess(cmdpath, NULL, NULL, NULL, TRUE, NULL, NULL, NULL, &s_info, &pro_info))
	{
		winerr();
		CloseHandle(hwexe);
		CloseHandle(hrexe);
		return 1;
	}

	cout << "开始读写管道...." << endl;
	cout << "注意:为了完整读取例如 ping等需要等待时间的命令的返回数据在输入数据后会有5秒延迟" << endl 
		 << "输入END即退出该程序" << endl;

	//---注意!!!  CMD是ASCII编码用WCHAR(UNICODE编码)会乱码
	char rbuf[2048];
	unsigned long rn = 0, wn = 0;
	//----------------------------读写管道----------------------------
	do
	{
		do
		{
			if (!PeekNamedPipe(hrexe, NULL, NULL, NULL, &rn, 0))	//管道是否有数据可读
			{
				cout << "nodata" << endl;
				winerr();
				break;
			}
			if ((rn>0)&&(rn<2048))
			{
				memset(rbuf, 0, 2048);
				if (!ReadFile(hrexe, rbuf, rn, NULL, NULL))
				{
					cout << "读管道错误" << endl;
					winerr();
					break;
				}
				else
				{
					cout << rbuf;
				}
			}
			Sleep(1000);
		} while (rn!=0);
		//---------写管道---------
		string wbuf;
		getline(cin, wbuf);
		if (wbuf=="END")
		{
			break;
		}
		wbuf += "\r\n";
		if (!WriteFile(hwexe, wbuf.c_str(), strlen(wbuf.c_str()), &wn, NULL))
		{
			cout << "写管道错误" << endl;
			winerr();
			break;
		}
		else
		{
			cout << wbuf;
		}
		Sleep(500);
	} while (true);
	
	TerminateProcess(pro_info.hProcess, 0);		//用于关闭cmd进程
	return 0;

}

inline void winerr(void)
{
	cout << "win error:" << GetLastError() << endl;
}

// 运行程序: Ctrl + F5 或调试 >“开始执行(不调试)”菜单
// 调试程序: F5 或调试 >“开始调试”菜单

// 入门提示: 
//   1. 使用解决方案资源管理器窗口添加/管理文件
//   2. 使用团队资源管理器窗口连接到源代码管理
//   3. 使用输出窗口查看生成输出和其他消息
//   4. 使用错误列表窗口查看错误
//   5. 转到“项目”>“添加新项”以创建新的代码文件,或转到“项目”>“添加现有项”以将现有代码文件添加到项目
//   6. 将来,若要再次打开此项目,请转到“文件”>“打开”>“项目”并选择 .sln 文件

           

!!!最后我其实也不是特别懂,如果有错误欢迎指出。

继续阅读