C++匿名管道详解及简单案例(基于VS2013)

首先放一张程序的运行图(程序下载地址),这里是父进程的一个命令行执行情况:


父进程的源文档中已经将子进程的执行程序放在了相对路径下,各位下载后直接运行父进程进行Debug即可得到效果,子进程程序供学习参考使用,这里先放上父进程的代码:

int main(int argc, char* argv[])
{

	SECURITY_ATTRIBUTES sa;  //定义一个安全结构体类型的变量Sa
	sa.bInheritHandle = TRUE;//让子进程可以继承父进程创建的匿名管道的读写句柄
	sa.lpSecurityDescriptor = NULL;//让系统为创建的匿名管道赋予默认的安全描述符
	sa.nLength = sizeof(SECURITY_ATTRIBUTES);//得到结构体(SECURITY_ATTRIBUTES)的长度
	if (!CreatePipe(&hRead, &hWrite, &sa, 0))//判断创建匿名管道是否成功
	{
		cout << "创建匿名管道失败!\n";
		return 0;
	}
	else
		cout << "成功创建匿名管道!\n";
	//如果创建匿名管道成功,就启动子进程,并将匿名管道的读写句柄传递给子进程
	STARTUPINFO sui;//创建子进程的函数需要的一个结构体类型的值
	PROCESS_INFORMATION pi;
	ZeroMemory(&sui, sizeof(STARTUPINFO));//将其余的成员全部置零,避免造成不好的影响
	sui.cb = sizeof(STARTUPINFO);//cb用来存放结构体变量STARTUPINFO的长度
	sui.dwFlags = STARTF_USESTDHANDLES;//标志成员,表示当前STARTUPINFO结构体的标准输入,标准输出和标准错误句柄有用
	sui.hStdInput = hRead;
	sui.hStdOutput = hWrite;//将子进程的标准输入输出句柄分别设置为管道的读、写句柄
	sui.hStdError = GetStdHandle(STD_ERROR_HANDLE);
	sui.wShowWindow = SW_SHOW; //隐藏命令行窗口
	sui.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
	WriteMsg();
	if (!CreateProcess(NULL, "child.exe", NULL, NULL,
		TRUE, 0, NULL, NULL, &sui, &pi))//创建子进程(十个参数)
	{
		CloseHandle(hRead);
		CloseHandle(hWrite);//关闭句柄,将内核对象的使用计数减少1,这样当操作系统发现内核对象的使用计数为0时,将清除内核对象。
		hRead = NULL;
		hWrite = NULL;
		cout << "创建子进程失败!";
		return 0;
	}
	else
	{
		CloseHandle(pi.hProcess);
		CloseHandle(pi.hThread);
	}


	Sleep(200);
	ReadMsg();
	return 0;
}

在说明创建函数之前我们需要先了解程序代码中涉及的几个结构体具体是干什么的(详细请查询库)

STARTUPINFO:用于指定新进程的主窗口特性的一个结构。
SECURITY_ATTRIBUTES:一个与安全相关的结构体。
PROCESS_INFORMATION:在创建进程时相关的数据结构之一,该结构返回有关新进程及其主线程的信息。

其余的代码的具体含义已经给予了非常详细的注释,这里只单说一下Create函数的各个参数的具体含义

CreateProcess("child.exe", NULL, NULL, NULL,TRUE, 0, NULL, NULL, &sui, &pi)
这里一共有十个参数
1、子进程应用程序的进程名
2、指定命令行参数,默认为NULL
3|4、进程和线程安全属性,默认为NULL,即使用系统默认安全属性
5、值为TRUE时,让父进程的每个可继承的打开句柄都能被子进程继承
6、创建标志,如不需要,置值为0
7、让新进程使用调用进程的环境、默认为NULL
8、让父进程和子进程拥有同样的驱动器和路径,默认为NULL
9、STARTUPINFO结构体实例化对象的地址(sui地址)
10、PROCESS_INFORMATION的地址(pi地址)

读数据代码:

void ReadMsg()
{
	char buf1[512];
	DWORD dwRead;
	if (!ReadFile(hRead, buf1, 512, &dwRead, NULL))
	{
		cout<<"读取数据失败!";
		return;
	}
	else
	{
		cout << "管道中读取数据为:"<<buf1;
		system("pause");
	}
}

写数据代码:

void WriteMsg()
{
	char buf[100];
	cout << "请输入你要发给子进程的消息:\n";
	cin >> buf;
	DWORD dwWrite;
	if (!WriteFile(hWrite, buf, strlen(buf), &dwWrite, NULL))
	{
		cout << "写入数据失败!";
		return;
	}
	else
		cout << "成功写入数据!\n";
}

相对于父进程,子进程相应就要简单很多了:

子进程读信息:

void ReadMsg()
{

	DWORD dwRead;
	if (!ReadFile(hRead, buf, 100, &dwRead, NULL))
	{
		cout<<"读取数据失败!";
		return;
	}
	sprintf(buf1, "子进程返回的数据为 %s!\n", buf);
	return;
}

子进程写信息:

void WriteMsg()
{
	DWORD dwWrite;
	if (!WriteFile(hWrite, buf1, strlen(buf1) + 1, &dwWrite, NULL))
	{
		cout << "写入数据失败!";
		return;
	}

}

子进程的主函数:

int main(int argc, char* argv[])
{
	hRead = GetStdHandle(STD_INPUT_HANDLE);//用于从一个特定的标准设备(标准输入、标准输出或标准错误)中取得一个句柄(用来标识不同设备的数值)
	hWrite = GetStdHandle(STD_OUTPUT_HANDLE);
	ReadMsg();
	Sleep(200);
	WriteMsg();
	return 0;
}


猜你喜欢

转载自blog.csdn.net/qq_15029743/article/details/79492645