MFC:进程间通信

来源:互联网 发布:got it 和get it的区别 编辑:程序博客网 时间:2024/05/29 03:15
windows下进程间通信方式:1、剪贴板(Ctrl+C;Ctrl+V) 2、匿名管道 3、命名管道 4、邮槽/****************************************************************************************/一、剪贴板:void CClipboardDlg::OnBtnSend() //向剪贴板中放置数据{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); //锁定内存对象,维护一个锁计数加一,不可移动除非GlobalReAllocstrcpy(pBuf,str);GlobalUnlock(hClip);//解锁内存对象,GlobalUnlock将锁计数减一SetClipboardData(CF_TEXT,hClip);//以指定的剪贴板格式向剪贴板中放置数据CloseClipboard(); //关闭剪贴板}}void CClipboardDlg::OnBtnRecv() //从剪贴板中获取数据{if(OpenClipboard()){if(IsClipboardFormatAvailable(CF_TEXT)){HANDLE hClip;char *pBuf;hClip=GetClipboardData(CF_TEXT); //获取剪贴板数据pBuf=(char*)GlobalLock(hClip);GlobalUnlock(hClip);SetDlgItemText(IDC_EDIT_RECV,pBuf);CloseClipboard();}}}/****************************************************************************************/二、匿名管道(CreatePipe)://匿名管道只能在本地机器上、在父子进程中通信,且子进程必须由父进程启动1、父进程中://构造析构中hRead = NULL;hWrite = NULL; if(hRead) CloseHandle(hRead); if(hWrite) CloseHandle(hWrite);void CParentView::OnPipeCreate() //创建匿名管道,创建子进程{SECURITY_ATTRIBUTES sa;sa.bInheritHandle=TRUE; //可以被一个新的进程继承其读写句柄sa.lpSecurityDescriptor=NULL;//默认的安全描述符sa.nLength=sizeof(SECURITY_ATTRIBUTES);if(!CreatePipe(&hRead,&hWrite,&sa,0)) //创建匿名管道{MessageBox("创建匿名管道失败!");return;}STARTUPINFO sui; //这个结构体成员真TM的多PROCESS_INFORMATION pi;ZeroMemory(&sui,sizeof(STARTUPINFO)); //将结构体中的所有成员置0sui.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; //置为NULL,析构就不必执行了hWrite=NULL;MessageBox("创建子进程失败!");return;}else{CloseHandle(pi.hProcess);//在不需要使用内核对象句柄时关闭句柄,引用计数变为1CloseHandle(pi.hThread);//切记,勿忘!}}void CParentView::OnPipeRead() //从管道中读数据{char buf[100];DWORD dwRead;if(!ReadFile(hRead,buf,100,&dwRead,NULL)) //可从文件管道控制台读数据{MessageBox("读取数据失败!");return;}MessageBox(buf);}void CParentView::OnPipeWrite() //向管道中写数据{char buf[]="这是父进程通过管道发送的数据:\nhttp://weibo.com/231237992/home";DWORD dwWrite; //实际写入的字节数if(!WriteFile(hWrite,buf,strlen(buf)+1,&dwWrite,NULL)){MessageBox("写入数据失败!");return;}}2、子进程中://添加到当前项目,且和父进程在同一目录下//构造析构同父进程void CChildView::OnInitialUpdate() //窗口完全创建成功后第一个调用的函数{CView::OnInitialUpdate();//获取子进程的标准输入和标准输出句柄,即得到管道的读取和写入句柄hRead=GetStdHandle(STD_INPUT_HANDLE);hWrite=GetStdHandle(STD_OUTPUT_HANDLE);}void CChildView::OnPipeRead() {char buf[100];DWORD dwRead;if(!ReadFile(hRead,buf,100,&dwRead,NULL)){MessageBox("读取数据失败!");return;}MessageBox(buf);}void CChildView::OnPipeWrite() {char buf[]="这是子进程通过管道写入的数据";DWORD dwWrite;if(!WriteFile(hWrite,buf,strlen(buf)+1,&dwWrite,NULL)){MessageBox("写入数据失败!");return;}}/****************************************************************************************/三、命名管道(CreateNamedPipe)://若要创建命名管道的多个实例,就要多次调用CreateNamedPipe;//命名管道是通过网络来完成进程间的通信,它屏蔽了底层的网络协议细节,充分利用了WinNT和Win2000的安全机制。//将命名管道作为一种网络编程方案时,它实际上建立了一个客户机/服务器通信体系,并可靠传输数据////可以指定哪一组用户可以访问管道,哪一组不可访问,就不需编写用户身份验证的代码了;若用socket,需编码实现命名管道服务器和客户机的区别:1、服务器是唯一一个有权创建命名管道的进程,也只有它才能接受管道客户机的连接请求。而客户机只能同一个现成的命名管道服务器建立连接。2、命名管道服务器只能在NT或2000上创建,客户机不然。命名管道提供了两种基本通信模式:字节模式和消息模式。在字节模式中,数据以一个连续的字节流的形式在客户机和服务器之间流动。而在消息模式中,客户机和服务器则通过一系列不连续的数据单位进行数据的收发,每次在管道上发出一条消息后,它必须作为一条完整的消息读入。1、服务器端:void CNamedPipeSrvView::OnPipeCreate() {//.表示本地机器(远程服务器的名字),固定格式,MYPipe:自定义的管道名//管道是双向的|重叠模式(读写执行要花一段时间才能完成的函数会立刻返回,耗费时间的操作在后台执行)//eg:可同时在一个管道句柄上进行读取和写入操作//参数0:字节模式;此参数决定是字节模式还是消息模式//参数1:可创建的最大实例数(若想同时连接5个,需调用五次CreateNamedPipe)//输入输出缓冲区的buffer大小,缺省的超时值,安全属性hPipe=CreateNamedPipe("\\\\.\\pipe\\MyPipe", PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, 0,1,1024,1024,0,NULL);                  //创建命名管道if(INVALID_HANDLE_VALUE==hPipe) //注意返回值{MessageBox("创建命名管道失败!");hPipe=NULL;return;}HANDLE hEvent;hEvent=CreateEvent(NULL,TRUE,FALSE,NULL); //创建人工重置的事件对象if(!hEvent){MessageBox("创建事件对象失败!");CloseHandle(hPipe);hPipe=NULL;return;}OVERLAPPED ovlap; //若创建命名管道用了FILE_FLAG_OVERLAPPED,必须指定此结构体,包含一个人工重置的事件对象句柄ZeroMemory(&ovlap,sizeof(OVERLAPPED)); //将此结构体清零ovlap.hEvent=hEvent; //只需要使用此数据成员if(!ConnectNamedPipe(hPipe,&ovlap)) //等待客户端连接命名管道{if(ERROR_IO_PENDING!=GetLastError()){MessageBox("等待客户端连接失败!");CloseHandle(hPipe);CloseHandle(hEvent);hPipe=NULL;return;}}if(WAIT_FAILED==WaitForSingleObject(hEvent,INFINITE)) //等待事件对象变为有信号状态{MessageBox("等待对象失败!");CloseHandle(hPipe);CloseHandle(hEvent);hPipe=NULL;return;}CloseHandle(hEvent); //已经有一个客户端连接到命名管道的实例上}void CNamedPipeSrvView::OnPipeRead() {// TODO: Add your command handler code herechar buf[100];DWORD dwRead;if(!ReadFile(hPipe,buf,100,&dwRead,NULL)){MessageBox("读取数据失败!");return;}MessageBox(buf);}void CNamedPipeSrvView::OnPipeWrite() {// TODO: Add your command handler code herechar buf[]="既然选择远方,便只顾风雨兼程";DWORD dwWrite;if(!WriteFile(hPipe,buf,strlen(buf)+1,&dwWrite,NULL)){MessageBox("写入数据失败!");return;}}2、客户端://首先构造析构:...void CNamedPipeCltView::OnPipeConnect() {if(!WaitNamedPipe("\\\\.\\pipe\\MyPipe",NMPWAIT_WAIT_FOREVER)) //等待命名管道{MessageBox("当前没有可利用的命名管道实例!");return;}hPipe=CreateFile("\\\\.\\pipe\\MyPipe",GENERIC_READ | GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); //打开命名管道if(INVALID_HANDLE_VALUE==hPipe) //注意返回值{MessageBox("打开命名管道失败!");hPipe=NULL;return;}}void CNamedPipeCltView::OnPipeRead() {char buf[100];DWORD dwRead;if(!ReadFile(hPipe,buf,100,&dwRead,NULL)){MessageBox("读取数据失败!");return;}MessageBox(buf);}void CNamedPipeCltView::OnPipeWrite() {char buf[]="命名管道测试程序";DWORD dwWrite;if(!WriteFile(hPipe,buf,strlen(buf)+1,&dwWrite,NULL)){MessageBox("写入数据失败!");return;}}/****************************************************************************************/四、邮槽(CreateMailslot)://邮槽是基于广播通信体系设计出来的,采用无连接的不可靠的数据传输。//油槽是一种单向通信机制,创建邮槽的服务器进程读取数据,打开邮槽的客户机进程写入数据。//为保证邮槽能在各种win平台下正常工作,传输信息时,应将消息长度限制在424字节以下。//服务器进程:void CMailslotSrvView::OnMailslotRecv() {HANDLE hMailslot;hMailslot=CreateMailslot("\\\\.\\mailslot\\MyMailslot",0, //0表示消息可为任意大小MAILSLOT_WAIT_FOREVER,NULL);if(INVALID_HANDLE_VALUE==hMailslot)  //注意返回值(创建命名管道/创建文件){MessageBox("创建油槽失败!");return;}char buf[100];DWORD dwRead;if(!ReadFile(hMailslot,buf,100,&dwRead,NULL)){MessageBox("读取数据失败!");CloseHandle(hMailslot); //关闭邮槽句柄return;}MessageBox(buf);CloseHandle(hMailslot);//关闭邮槽句柄}//客户机进程:void CMailslotCltView::OnMailslotSend() {HANDLE hMailslot;hMailslot=CreateFile("\\\\.\\mailslot\\MyMailslot",GENERIC_WRITE,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); //打开邮槽文件if(INVALID_HANDLE_VALUE==hMailslot){MessageBox("打开油槽失败!");return;}char buf[]="I love you.";DWORD dwWrite;if(!WriteFile(hMailslot,buf,strlen(buf)+1,&dwWrite,NULL)) //向邮槽写数据{MessageBox("写入数据失败!");CloseHandle(hMailslot);return;}CloseHandle(hMailslot);}

0 0