双管道比但管道复杂一点,但是功能强大,能更快速的处理进程间的通信.
还是以单管道的例子,稍加修改即可
1.定义两个成员变量.
HANDLE m_hInReadPipe;//读取输入管道的内容
HANDLE m_hOutWritePipe;//把命令输出到输出管道
2.在构造函数中创建管道和进程
HANDLE hInWritePipe = nullptr;//把内容写到输入管道
HANDLE hOutReadPipe = nullptr;//从输出管道里读取命令
//管道的安全属性
SECURITY_ATTRIBUTES sa = { 0 };
sa.nLength = sizeof(sa);
sa.bInheritHandle = TRUE;//句柄可继承
sa.lpSecurityDescriptor = nullptr;//安全描述,设为null
//创建管道
//创建输出管道,就是把命令从编辑框中输出到命令框
BOOL bCreateOutPipe = CreatePipe(&hOutReadPipe, &m_hOutWritePipe, &sa, 0);
if (!bCreateOutPipe)
{
AfxMessageBox(TEXT("创建输出管道失败!"));
return;
}
//创建输入管道,命令框内容输入到编辑框中
BOOL bCreateInPipe = CreatePipe(&m_hInReadPipe, &hInWritePipe, &sa, 0);
if (!bCreateOutPipe)
{
AfxMessageBox(TEXT("创建输入管道失败!"));
return;
}
//进程信息结构
PROCESS_INFORMATION pi = { 0 };
//启动信息
STARTUPINFO si = { 0 };
si.cb = sizeof(STARTUPINFO);
//因为是双管道,所以命令从输出管道中读取
si.hStdInput = hOutReadPipe;
//输出到输入管道中
si.hStdOutput = si.hStdError = hInWritePipe;
si.wShowWindow = SW_HIDE;//隐藏进程窗口
si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
//创建进程 ,一开始就把命令框创建出来,szCmdLine是全局变量,初始化为cmd
BOOL bCreateProc = CreateProcess(nullptr, szCmdLine, nullptr,
nullptr, TRUE, 0, nullptr, nullptr, &si, &pi);
if (!bCreateProc)
{
AfxMessageBox(TEXT("创建进程失败!"));
return;
}
//不需要这两个句柄,关掉他们
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
//用完后关掉管道的另一端
CloseHandle(hInWritePipe);
CloseHandle(hOutReadPipe);
3.输出命令,读内容
//获取命令
GetDlgItemText(IDC_EDIT_CMD, szCmdLine, MAX_PATH * 2);
//添加换行符(回车),否则命令不能执行
strcat(szCmdLine, "\n");
//把命令输出到命令框
if (!WriteFile(m_hOutWritePipe, szCmdLine, strlen(szCmdLine), nullptr, nullptr))
return;
//给命令执行的时间,像ping这种命令,2秒是执行不完的,所以只能读回一部分数据
Sleep(2000);
//创建成功后,把管道的内容读取出来
//注意,只能用ASCII编码格式读,因为命令行窗口的内容都是ASCII编码的
//如果CString TCHAR 来读会乱码
char szBuffer[4096] = { 0 };
DWORD dwRead = 0;
//检查输入管道里面是否还有内容
while (PeekNamedPipe(m_hInReadPipe,szBuffer,4096,&dwRead,nullptr,0)
&& dwRead >0)
{
memset(szBuffer, 0, sizeof(szBuffer));
ReadFile(m_hInReadPipe, szBuffer, dwRead, nullptr, nullptr);
m_content += szBuffer;
}
//显示内容
UpdateData(FALSE);
4.关闭管道句柄
CMFCTESTDlg::~CMFCTESTDlg() { CloseHandle(m_hInReadPipe);
CloseHandle(m_hOutWritePipe);
}
这要就能运行的时候打开一个进程,然后直接通过管道输出命令,就不用每执行一次就创建一个新的进程.
要注意的是,给命令添加换行符的时候,这个换行符不能是unicode字符,因为命令窗口是ASCII码的,所以乱码后命令不能识别.
解决方法:项目->属性->字符集->改为未设置,这样TCHAR就会自动转换为char型,就能正确识别换行符.