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

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

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

详细讲解进程间通讯的四种方式_第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张图片

(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;
 }
}

你可能感兴趣的:(c++)