详细讲解进程间通讯的四种方式

2/22/2017来源:ASP.NET技巧人气:1550

进程间通讯的四种方式:剪贴板、匿名管道、命名管道和邮槽

第一种:剪贴板 (1)新建一个基于对话框的应用程序,并设置好如下界面:

\ (2)分别编辑发送按钮和接收按钮的代码: [cpp] ?void CClipboardDlg::OnBtnSend()   {      // TODO: Add your control notification handler code here       if(OpenClipboard())      {          CString str;          HANDLE hClip;          char *pBuf;          EmptyClipboard();//将剪贴板拥有权设置为当前窗口           GetDlgItemText(IDC_EDIT_SEND,str);          hClip=GlobalAlloc(GMEM_MOVEABLE,str.GetLength()+1);//多分配一个字节,用于放置回车           pBuf=(char *)GlobalLock(hClip);//对一个内存对象加锁并返回内存对象句柄           strcpy(pBuf,str);          GlobalUnlock(hClip);//解锁           SetClipboardData(CF_TEXT,hClip);//放置数据           CloseClipboard();//关闭剪贴板       }  }    void CClipboardDlg::OnBtnRecv()   {      // TODO: Add your control notification handler code here       if(OpenClipboard())      {          //The IsClipboardFormatAvailable function determines whether the clipboard contains data in the specified format           if(IsClipboardFormatAvailable(CF_TEXT))          {              HANDLE hClip;              char *pBuf;              hClip=GetClipboardData(CF_TEXT);              pBuf=(char *)GlobalLock(hClip);//The GlobalLock function locks a global memory object and returns a pointer to the first byte of the object's memory block               GlobalUnlock(hClip);              SetDlgItemText(IDC_EDIT_RECV,pBuf);              CloseClipboard();          }      }  } 

void CClipboardDlg::OnBtnSend() {  // TODO: Add your control notification handler code here  if(OpenClipboard())  {   CString str;   HANDLE hClip;   char *pBuf;   EmptyClipboard();//将剪贴板拥有权设置为当前窗口         GetDlgItemText(IDC_EDIT_SEND,str);   hClip=GlobalAlloc(GMEM_MOVEABLE,str.GetLength()+1);//多分配一个字节,用于放置回车         pBuf=(char *)GlobalLock(hClip);//对一个内存对象加锁并返回内存对象句柄         strcpy(pBuf,str);   GlobalUnlock(hClip);//解锁   SetClipboardData(CF_TEXT,hClip);//放置数据   CloseClipboard();//关闭剪贴板  } }

void CClipboardDlg::OnBtnRecv() {  // TODO: Add your control notification handler code here  if(OpenClipboard())  {   //The IsClipboardFormatAvailable function determines whether the clipboard contains data in the specified format   if(IsClipboardFormatAvailable(CF_TEXT))   {             HANDLE hClip;    char *pBuf;       hClip=GetClipboardData(CF_TEXT);    pBuf=(char *)GlobalLock(hClip);//The GlobalLock function locks a global memory object and returns a pointer to the first byte of the object's memory block    GlobalUnlock(hClip);    SetDlgItemText(IDC_EDIT_RECV,pBuf);    CloseClipboard();   }  } }

第二种:匿名管道 <1>新建一个基于单文档的工程,工程名为"Parent" (1)添加如下菜单项,并添加命令响应函数 CChildView::OnPipeRead()、CChildView::OnPipeWrite();

\ (2)在CParentView类中添加两个句柄HANDLE hRead 和 HANDLE hWrite,属性设为私有,并在构造函数中进行初始化,在析构函数中释放该句柄 [cpp] CParentView::CParentView()  {      // TODO: add construction code here       hRead=NULL;      hWrite=NULL;  }    CParentView::~CChildView()  {      if(hRead)         CloseHandle(hRead);      if(hWrite)         CloseHandle(hWrite);  } 

CParentView::CParentView() {  // TODO: add construction code here     hRead=NULL;     hWrite=NULL; }

CParentView::~CChildView() {  if(hRead)     CloseHandle(hRead);  if(hWrite)     CloseHandle(hWrite); }

(3)编写CParentView::OnPipeCreate() 函数,注意用到两个函数CreatePipe(...)和CreatePRocess(...)分别用于创建管道和启动子进程。代码如下: [cpp] void CParentView::OnPipeCreate()   {      // TODO: Add your command handler code here       SECURITY_ATTRIBUTES sa;//定义一个安全属性结构图       sa.bInheritHandle=TRUE;//TRUE表示可以被子进程继承       sa.lpSecurityDescriptor=NULL;      sa.nLength=sizeof(SECURITY_ATTRIBUTES);      if(CreatePipe(&hRead,&hWrite,&sa,0))//创建匿名管道       {          MessageBox("匿名管道创建失败!");          return ;      }     //如果创建成功则启动子进程,将匿名管道的读写句柄传递给子进程      STARTUPINFO sui;     PROCESS_INFORMATION pi;     ZeroMemory(&sui,sizeof(STARTUPINFO));//将这个结构体内的所有成员设为0      sui.cb=sizeof(STARTUPINFO);     sui.dwFlags=STARTF_USESTDHANDLES;     sui.hStdInput=hRead;     sui.hStdOutput=hWrite;     sui.hStdError=GetStdHandle(STD_ERROR_HANDLE);     if(!CreateProcess("..\\Child\\Debug\\Child.exe",NULL,NULL,NULL,               TRUE,0,NULL,NULL,&sui,&pi))     {         CloseHandle(hRead);         CloseHandle(hWrite);         hRead=NULL;         hWrite=NULL;         MessageBox("创建子进程失败!");         return;       }     else     {         CloseHandle(pi.hProcess);//关闭主进程句柄          CloseHandle(pi.hThread);//关闭主进程线程句柄       }       } 

void CParentView::OnPipeCreate() {  // TODO: Add your command handler code here  SECURITY_ATTRIBUTES sa;//定义一个安全属性结构图  sa.bInheritHandle=TRUE;//TRUE表示可以被子进程继承  sa.lpSecurityDescriptor=NULL;  sa.nLength=sizeof(SECURITY_ATTRIBUTES);  if(CreatePipe(&hRead,&hWrite,&sa,0))//创建匿名管道  {         MessageBox("匿名管道创建失败!");   return ;  }    //如果创建成功则启动子进程,将匿名管道的读写句柄传递给子进程    STARTUPINFO sui;    PROCESS_INFORMATION pi;    ZeroMemory(&sui,sizeof(STARTUPINFO));//将这个结构体内的所有成员设为0    sui.cb=sizeof(STARTUPINFO);    sui.dwFlags=STARTF_USESTDHANDLES;    sui.hStdInput=hRead;    sui.hStdOutput=hWrite;    sui.hStdError=GetStdHandle(STD_ERROR_HANDLE);    if(!CreateProcess("..\\Child\\Debug\\Child.exe",NULL,NULL,NULL,           TRUE,0,NULL,NULL,&sui,&pi))    {     CloseHandle(hRead);     CloseHandle(hWrite);     hRead=NULL;     hWrite=NULL;     MessageBox("创建子进程失败!");     return;

   }    else    {     CloseHandle(pi.hProcess);//关闭主进程句柄     CloseHandle(pi.hThread);//关闭主进程线程句柄    }    }(4)编写OnPipeRead()和OnPipeWrite()的具体实现: [cpp] void CParentView::OnPipeRead()   {      // TODO: Add your command handler code here       char buf[100];      DWord dwRead;      if(!ReadFile(hRead,buf,100,&dwRead,NULL))      {          MessageBox("读取数据失败!");          return;      }      MessageBox(buf);  }    void CParentView::OnPipeWrite()   {      // TODO: Add your command handler code here       char buf[]="http://www.sunxin.org";      DWORD dwWrite;      if(!WriteFile(hWrite,buf,strlen(buf)+1,&dwWrite,NULL))      {          MessageBox("写入数据失败!");          return;      }  } 

void CParentView::OnPipeRead() {  // TODO: Add your command handler code here  char buf[100];  DWORD dwRead;  if(!ReadFile(hRead,buf,100,&dwRead,NULL))  {   MessageBox("读取数据失败!");   return;  }  MessageBox(buf); }

void CParentView::OnPipeWrite() {  // TODO: Add your command handler code here  char buf[]="http://www.sunxin.org";  DWORD dwWrite;  if(!WriteFile(hWrite,buf,strlen(buf)+1,&dwWrite,NULL))  {   MessageBox("写入数据失败!");   return;  } }

 

 

<2>在该工程中再添加一个项目,同样是基于单文档的,项目名为"Child",于"Parent"保持平级即可。 (1)添加如下菜单项,并添加命令响应函数 CChildView::OnPipeRead()、CChildView::OnPipeWrite();

(2)首先我们要获得子进程的标准输入和标准输出句柄,这个可以在CChildView类的窗口完全创建的时候去获取,此时我们可以用一个CChildView::OnInitialUpdate()的虚函数去获取,OnInitialUpdate()是在窗口完全创建之后第一个执行的函数。 (3)在CChildView类中添加两个句柄 HANDLE hRead 和 HANDLE hWrite,属性设为私有,并在构造函数中进行初始化,在析构函数中释放该句柄 [cpp] CChildView::CChildView()  {      // TODO: add construction code here       hRead=NULL;      hWrite=NULL;  }    CChildView::~CChildView()  {      if(hRead)         CloseHandle(hRead);      if(hWrite)         CloseHandle(hWrite);  } 

CChildView::CChildView() {  // TODO: add construction code here     hRead=NULL;     hWrite=NULL; }

CChildView::~CChildView() {  if(hRead)     CloseHandle(hRead);  if(hWrite)     CloseHandle(hWrite); }(4)在OnInitialUpdate()函数中通过 GetStdHandle(STD_INPUT_HANDLE)、GetStdHandle(STD_OUTPUT_HANDLE)得到标准输入输出句柄 [cpp] hRead=GetStdHandle(STD_INPUT_HANDLE);//得到管道的读取句柄   hWrite=GetStdHandle(STD_OUTPUT_HANDLE);//得到管道的写入句柄 

 hRead=GetStdHandle(STD_INPUT_HANDLE);//得到管道的读取句柄  hWrite=GetStdHandle(STD_OUTPUT_HANDLE);//得到管道的写入句柄(5)接着编写读取进程OnPipeRead()和写入进程OnPipeWrite()代码的具体实现: [cpp] void CChildView::OnPipeRead()   {      // TODO: Add your command handler code here       char buf[100];      DWORD dwRead;      if(!ReadFile(hRead,buf,100,&dwRead,NULL))      {          MessageBox("读取数据失败!");          return;      }      MessageBox(buf);  }    void CChildView::OnPipeWrite()   {      // TODO: Add your command handler code here       char buf[]="匿名管道测试程序";      DWORD dwWrite;      if(!WriteFile(hWrite,buf,strlen(buf)+1,&dwWrite,NULL))      {          MessageBox("写入数据失败!");          return;      }  } 

void CChil\ dView::OnPipeRead() {  // TODO: Add your command handler code here  char buf[100];  DWORD dwRead;  if(!ReadFile(hRead,buf,100,&dwRead,NULL))  {   MessageBox("读取数据失败!");   return;  }  MessageBox(buf); }

void CChildView::OnPipeWrite() {  // TODO: Add your command handler code here  char buf[]="匿名管道测试程序";  DWORD dwWrite;  if(!WriteFile(hWrite,buf,strlen(buf)+1,&dwWrite,NULL))  {   MessageBox("写入数据失败!");   return;  } }