进程间通信---管道

网上有大量的关于管道的理论文章,在此不再赘述,最近在做一个通信上的项目,正好用到管道-------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);    //接个\0
110 
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_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 += "\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 }
View Code

客户端代码

  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 }
View Code

 

posted @ 2017-02-15 16:55  卷珠帘  阅读(241)  评论(0编辑  收藏  举报