进程间通信

进程间通信

1.剪贴板

新建一个MFC基于单文档的应用程序,取名:Clipboard,然后编辑对话框资源,如下图:

双击发送按钮,添加消息响应函数,编辑:

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);//
str中的数据拷贝到内存中 
        GlobalUnlock(hClip);//
解锁 
        SetClipboardData(CF_TEXT,hClip);//
将数据设置到剪贴板上 
        CloseClipboard();//
关闭剪贴板 
    }
 
}

双击接收按钮,添加消息响应函数,编辑:

void CClipboardDlg::OnBtnRecv()  

    // TODO: Add your control notification handler code here 
    if(OpenClipboard()) 
    { 
        if(IsClipboardFormatAvailable(CF_TEXT)) 
        { 
            HANDLE hClip; 
            char *pBuf; 
            hClip=GetClipboardData(CF_TEXT);//
获取剪贴板数据 
            pBuf=(char*)GlobalLock(hClip); //
给句柄加锁后,存到pBuf
            GlobalUnlock(hClip); //解锁
            SetDlgItemText(IDC_EDIT_RECV,pBuf); //
将数据设置到pBuf
            CloseClipboard(); 
        } 
    }
 
}

2.匿名管道

父进程:

新建一个MFC的单文档应用程序,取名:Parent,编辑资源,如下图:

并分别对这三个菜单添加命令消息响应函数,再在CParentView类上添加两个成员变量,

private
    HANDLE hWrite; 
    HANDLE hRead;
 

再在构造函数中初始化,在析构函数中关闭句柄,如下:

CParentView::CParentView() 

    // TODO: add construction code here 
        hRead=NULL; 
        hWrite=NULL;
 

 
CParentView::~CParentView() 

    if(hRead) 
        CloseHandle(hRead);//
关闭读句柄 
    if(hWrite) 
        CloseHandle(hWrite);//
关闭写句柄 
}

编辑三个菜单添加命令消息响应函数:

void CParentView::OnPipeCreate()  

    // TODO: Add your command handler code here 
    SECURITY_ATTRIBUTES sa; 
    sa.bInheritHandle=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));//
把结构体STARTUPINFO所有成员赋值为
    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::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.baidu.com"
    DWORD dwWrite; 
    if(!WriteFile(hWrite,buf,strlen(buf)+1,&dwWrite,NULL)) 
    { 
        MessageBox("
写入数据失败!"); 
        return
    }
 
}

子进程:

Workspace 'Parent'上点右键 -> Add New Project To Wordspace… ,新建一个MFC单文档应用程序,取名Child,编辑菜单资源,如下图:

然后分别对这两个菜单项添加消息响应函数,并CChildView类上添加一个OnInitialUpdate虚函数,再添加两个成员变量:

private
    HANDLE hRead; 
    HANDLE hWrite;
 

在构造函数和析构函数中:

CChildView::CChildView() 

    // TODO: add construction code here 
    hRead=NULL;  
    hWrite=NULL;
  

 
CChildView::~CChildView() 

    if(hRead) 
        CloseHandle(hRead);//
关闭读句柄 
    if(hWrite) 
        CloseHandle(hWrite);//
关闭写句柄 
}

然后在ChildView.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 CChildView::OnInitialUpdate()  

    CView::OnInitialUpdate(); 
    // TODO: Add your specialized code here and/or call the base class 
    hRead=GetStdHandle(STD_INPUT_HANDLE);//
得到标准输入句柄 
    hWrite=GetStdHandle(STD_OUTPUT_HANDLE);//
得到标准输出句柄 
}

3.命名管道

服务端:

新建一个MFC的单文档应用程序,取名:NamedPipeSrv,编辑资源,如下图:

并分别对这三个菜单添加命令消息响应函数,再在CNamedPipeSrvView类上添加一个成员变量:

private
    HANDLE hPipe;

在构造函数和析构函数中编辑:

CNamedPipeSrvView::CNamedPipeSrvView() 

    hPipe=NULL; 

 
CNamedPipeSrvView::~CNamedPipeSrvView() 

    if(hPipe) 
        CloseHandle(hPipe);//
关闭这个句柄 
}

NamedPipeSrvView.cpp中编辑:

void CNamedPipeSrvView::OnPipeCreate()  

    // TODO: Add your command handler code here 
    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; 
    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 here 
    char buf[100]; 
    DWORD dwRead; 
    if(!ReadFile(hPipe,buf,100,&dwRead,NULL)) 
    { 
        MessageBox("
读取数据失败!"); 
        return
    } 
    MessageBox(buf);
 

 
void CNamedPipeSrvView::OnPipeWrite()  

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

客户端:

Workspace 'NamedpipeSrv'上点右键 -> Add New Project To Wordspace… ,新建一个MFC单文档应用程序,取名NamedPipeClt,编辑菜单资源,如下图:

然后分别对这两个菜单项添加消息响应函数,并CNamedPipeCltView类上添加一个成员变量:

private
    HANDLE hPipe;
 

并在构造函数和析构函数中编辑:

CNamePipeCltView::CNamePipeCltView() 

    hPipe=NULL; 

 
CNamePipeCltView::~CNamePipeCltView() 

    if(hPipe) 
    CloseHandle(hPipe);//
关闭句柄  
}

编辑NamePipeCltView.cpp:

void CNamePipeCltView::OnPipeConnect()  

    // TODO: Add your command handler code here 
    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 CNamePipeCltView::OnPipeRead()  

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

 
void CNamePipeCltView::OnPipeWrite()  

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

4.利用邮槽完成进程间通信

服务器端:

新建一个MFC单文档应用程序,取名:MailSlotSrv,编辑菜单资源,添加一个接收数据菜单项,并取消弹出菜单项,如下图:

再给接收菜单添加命令消息响应,编辑:

void CMailSlotSrvView::OnMailslotRecv()  

    // TODO: Add your command handler code here 
    HANDLE hMailslot; 
    hMailslot=CreateMailslot("\\\\.\\mailslot\\MyMailslot",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);
 
}

客户端:

Workspace 'MailSlotSrv'上点右键 -> Add New Project To Wordspace… ,新建一个MFC单文档应用程序,取名MailslotClt,编辑菜单资源,添加一个发送数据菜单项,并取消弹出菜单项,如下图:

并这个菜单项添加命令消息响应函数,编辑:

void CMailslotCltView::OnMailslotSend()  

    // TODO: Add your command handler code here 
    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[]="
邮槽测试程序"
    DWORD dwWrite; 
    if(!WriteFile(hMailslot,buf,strlen(buf)+1,&dwWrite,NULL)) 
    { 
        MessageBox("
写入数据失败!"); 
        CloseHandle(hMailslot); 
        return
    } 
    CloseHandle(hMailslot);
 
}

运行, OK !

 

原文地址:https://www.cnblogs.com/luowei010101/p/2030837.html