进程间通讯的四种方式:剪贴板、匿名管道、命名管道和邮槽
第一种:剪贴板
(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;
}
}