本文共 8410 字,大约阅读时间需要 28 分钟。
上面红色框框中文本是在DOS窗口下输出的,可以通过管道将DOS程序的输出在界面文本编辑框进行输出。 这里需要介绍CreatePipe()函数,它的原型为
BOOL WINAPI CreatePipe( __out PHANDLE hReadPipe, //参数 hReadPipe 为输出参数,该句柄代表管道的读取句柄。 __out PHANDLE hWritePipe, //参数 hWritePipe 为输出参数,该句柄代表管道的写入句柄 __in LPSECURITY_ATTRIBUTES lpPipeAttributes, //参数 lpPipeAttributes 为一个输入参数,指向一个 SECURITY_ATTRIBUTES 的结构体指针 __in DWORD nSize //管道的缓存大小 );
这里由于是父子进程的关系,需要对SECURITY_ATTRIBUTES结构体进行设置,它的原型为
typedef struct _SECURITY_ATTRIBUTES { DWORD nLength; //结构体大小 LPVOID lpSecurityDescriptor; // BOOL bInheritHandle; //由于是父子进程,一定要设置为True,允许继承} SECURITY_ATTRIBUTES, *PSECURITY_ATTRIBUTES, *LPSECURITY_ATTRIBUTES;
HANDLE m_hPipeWrite; //管道写数据句柄 HANDLE m_hPipeRead; //管道读数据句柄 void my_PipeInit(); bool my_CreateProcess(); //创建进程 bool my_CreatePipe(); //创建管道 void my_SendDataPipe(CString data); //通过管道发送数据 void SetStartInfo(STARTUPINFO& si); //初始化启动信息 void SetSecurity_attr(SECURITY_ATTRIBUTES& ps); //初始化安全属性 static DWORD WINAPI Pipe_Listen(LPVOID lpParameter); //接收管道数据线程在OnInitDialog()中调用初始化函数my_PipeInit()。
void CPipeServer_MFCDlg::my_PipeInit(){ if (!my_CreatePipe()) return; if (!my_CreateProcess()) return; //HANDLE hThread = CreateThread(NULL, 0, Pipe_Listen, &m_hPipeRead, 0, NULL); //创建socket的发送线程 //关闭该接收线程句柄,释放引用计数 //CloseHandle(hThread);}//************************************************************************// 函数名称: SetProcessInfo// 访问权限: public // 创建日期: 2017/06/05// 创 建 人: // 函数说明: 初始化SECURITY_ATTRIBUTES结构体// 函数参数: PSECURITY_ATTRIBUTES & ps 需要初始化的SECURITY_ATTRIBUTES结构体// 返 回 值: void//************************************************************************void CPipeServer_MFCDlg::SetSecurity_attr(SECURITY_ATTRIBUTES& ps){ //这里必须将 bInheritHandle 设置为 TRUE, //从而使得子进程可以继承父进程创建的匿名管道的句柄 ps.bInheritHandle = TRUE; ps.lpSecurityDescriptor = NULL; ps.nLength = sizeof(SECURITY_ATTRIBUTES);}//************************************************************************// 函数名称: SetStartInfo// 访问权限: public // 创建日期: 2017/06/05// 创 建 人: // 函数说明: 初始化STARTUPINFO结构体// 函数参数: STARTUPINFO & si 需要初始化的STARTUPINFO结构体// 返 回 值: void//************************************************************************void CPipeServer_MFCDlg::SetStartInfo(STARTUPINFO& si){ memset(&si, 0, sizeof(STARTUPINFO)); si.cb = sizeof(STARTUPINFO); si.wShowWindow = SW_SHOW; si.dwFlags = STARTF_USESTDHANDLES;//STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES; //子进程的标准输入句柄为父进程管道的读数据句柄 si.hStdInput = m_hPipeRead; //子进程的标准输出句柄为父进程管道的写数据句柄 si.hStdOutput = m_hPipeWrite; //子进程的标准错误处理句柄和父进程的标准错误处理句柄一致 si.hStdError = HANDLE(STD_ERROR_HANDLE);}//************************************************************************// 函数名称: my_CreatePipe// 访问权限: public // 创建日期: 2017/06/05// 创 建 人: // 函数说明: 创建匿名管道// 返 回 值: bool//************************************************************************bool CPipeServer_MFCDlg::my_CreatePipe(){ SECURITY_ATTRIBUTES sa; SetSecurity_attr(sa); if (!CreatePipe(&m_hPipeRead, &m_hPipeWrite, &sa, 0)) { MessageBox(_T("create anonymous pipe failed")); return false; } return true;}//************************************************************************// 函数名称: my_SendDataPipe// 访问权限: public // 创建日期: 2017/06/05// 创 建 人: // 函数说明: 通过管道发送数据// 函数参数: std::string data 需要发送的数据// 返 回 值: void//************************************************************************void CPipeServer_MFCDlg::my_SendDataPipe(CString data){ DWORD data_write; //写入数据 if (!WriteFile(m_hPipeWrite, (LPCTSTR)data, data.GetLength()*2, &data_write, NULL)) { MessageBox(_T("client send data:")); }}//************************************************************************// 函数名称: my_CreateProcess// 访问权限: public // 创建日期: 2017/06/05// 创 建 人: // 函数说明: 创建进程// 返 回 值: bool//************************************************************************bool CPipeServer_MFCDlg::my_CreateProcess(){ PROCESS_INFORMATION pi = {0}; STARTUPINFO si; SetStartInfo(si); LPWSTR exe_path = _T("E:\\C++_SQL_program\\ProcessesThreads\\AnonymousPipe\\AnonymousPipeClient\\PipeClient\\Debug\\PipeClient_MFC.exe"); BOOL kk = CreateProcess(exe_path, NULL, NULL, NULL, TRUE, NULL, NULL, NULL, &si, &pi); if (!kk) { MessageBox(_T("create process failed")); CloseHandle(m_hPipeWrite); //创建进程失败,关闭读写句柄 CloseHandle(m_hPipeRead); return false; } //由于结构体pi中的数据已经使用不到了,将其资源释放 CloseHandle(pi.hProcess); CloseHandle(pi.hThread); return true;}//************************************************************************// 函数名称: Pipe_Listen// 访问权限: public // 创建日期: 2017/06/05// 创 建 人: // 函数说明: 监听管道的数据// 函数参数: LPVOID lpParameter// 返 回 值: DWORD WINAPI//************************************************************************DWORD WINAPI CPipeServer_MFCDlg::Pipe_Listen(LPVOID lpParameter){ HANDLE* PipeRead = (HANDLE*)lpParameter; TCHAR data[4096] = {0}; DWORD data_read; while (true) { memset(data, 0, sizeof(data)); if (!ReadFile((HANDLE)(*PipeRead), data, 4096, &data_read, NULL)) continue; CString str(_T("client say:")); AfxGetApp()->m_pMainWnd->GetDlgItemText(IDC_EDIT_MsgHis, str); str += _T("client say:") + (CString)data + _T("\r\n"); AfxGetApp()->m_pMainWnd->SetDlgItemText(IDC_EDIT_MsgHis, str); //Sleep(200); } return data_read;}//发送数据void CPipeServer_MFCDlg::OnBnClickedButton1(){ // TODO: 在此添加控件通知处理程序代码 CString str; GetDlgItemText(IDC_EDIT_Msg, str); my_SendDataPipe(str);}
HANDLE m_hPipeWrite; //管道写数据句柄 HANDLE m_hPipeRead; //管道读数据句柄 void my_PipeInit(); //初始化管道 bool my_GetParentPipeHandle(); //创建管道 void my_SendDataPipe(CString data); //通过管道发送数据 static DWORD WINAPI Pipe_Listen(LPVOID lpParameter); //接收管道数据线程在 OnInitDialog()中调用初始化函数my_PipeInit()。
void CPipeClient_MFCDlg::my_PipeInit(){ if (!my_GetParentPipeHandle()) return; //初始化管道 HANDLE hThread = CreateThread(NULL, 0, Pipe_Listen, &m_hPipeRead, 0, NULL); //创建socket的发送线程 //关闭该接收线程句柄,释放引用计数 CloseHandle(hThread);}//************************************************************************// 函数名称: my_GetParentPipeHandle// 访问权限: public // 创建日期: 2017/06/05// 创 建 人: // 函数说明: 使用父进程继承下来的输入输出句柄初始化读写句柄// 返 回 值: bool//************************************************************************bool CPipeClient_MFCDlg::my_GetParentPipeHandle(){ m_hPipeRead = GetStdHandle(STD_INPUT_HANDLE); m_hPipeWrite = GetStdHandle(STD_OUTPUT_HANDLE); if (INVALID_HANDLE_VALUE == m_hPipeRead || INVALID_HANDLE_VALUE == m_hPipeWrite) { MessageBox(_T("从父进程获得管道读写句柄失败")); CloseHandle(m_hPipeRead); CloseHandle(m_hPipeWrite); return false; } return true;}//************************************************************************// 函数名称: my_SendDataPipe// 访问权限: public // 创建日期: 2017/06/05// 创 建 人: // 函数说明: 通过管道发送数据// 函数参数: std::string data 需要发送的数据// 返 回 值: void//************************************************************************void CPipeClient_MFCDlg::my_SendDataPipe(CString data){ DWORD data_write; //写入数据 if (!WriteFile(m_hPipeWrite, (LPCTSTR)data, data.GetLength()*2, &data_write, NULL)) { MessageBox(_T("发送信息失败")); }}//************************************************************************// 函数名称: Pipe_Listen// 访问权限: public // 创建日期: 2017/06/05// 创 建 人: // 函数说明: 创建一个管道监听线程,将接收到的数据显示到窗口界面上// 函数参数: LPVOID lpParameter// 返 回 值: DWORD WINAPI//************************************************************************DWORD WINAPI CPipeClient_MFCDlg::Pipe_Listen(LPVOID lpParameter) //接收管道数据线程{ HANDLE* PipeRead = (HANDLE*)lpParameter; TCHAR data[4096] = { 0 }; DWORD data_read; while (true) { memset(data, 0, sizeof(data)); if (!ReadFile((HANDLE)(*PipeRead), data, 4096, &data_read, NULL)) continue; CString str(_T("server say:")); AfxGetApp()->m_pMainWnd->GetDlgItemText(IDC_EDIT_MsgHis, str); str += _T("server say:") + (CString)data + _T("\r\n"); AfxGetApp()->m_pMainWnd->SetDlgItemText(IDC_EDIT_MsgHis, str); //Sleep(200); } return data_read;}//发送数据void CPipeClient_MFCDlg::OnBnClickedButton1(){ // TODO: 在此添加控件通知处理程序代码 CString str; GetDlgItemText(IDC_EDIT_Msg, str); my_SendDataPipe(str);}