进程间的通信
位于同一个进程中的多个线程共享同一个地址空间,因此线程之间的通信非常简单。然而,由于每个进程所拥有的4GB地址空间都是私有的,一个进程不能访问另一个进程地址空间中的数据,因此进程间的通信就比较困难。SOCKET也是进程间通信的一种方式(详见http://blog.csdn.net/walkerkalr/article/details/19443921)。本文将讲述进程间通信的其他方式(剪贴板,匿名管道,命名管道,油槽)。
1.剪贴板
剪贴板实际上是系统维护管理的一块内存区域,当在一个进程中复制数据时,是将这个数据放到该块内存区域中,当在另一个进程中黏贴数据时,是从该内存块区域中取出数据,然后显示在窗口上。
编写利用剪贴板通信的程序:
1)新建一个基于对话框的应用程序,工程名取为Clipboard
2)设计对话框界面
编辑框IDC_EDIT_SEND
编辑框IDC_EDIT_RECV
按钮IDC_BTN_SEND
按钮IDC_BTN_RECV
3)数据发送程序块设计
1>在把数据放置到剪贴板之前,首先需要打开剪贴板,这可以利用CWnd类的OpenClipBorad成员函数实现,该函数的原型声明如下:
BOOL OpenClipboard( );
如果某个程序打开了剪贴板,则其他程序将不能修改剪贴板,直到前者调用了BOOL CloseClipboar(),并且只有调用了BOOL EmptyClipboard(void)函数清空剪贴板,并释放剪贴板中数据的句柄,然后剪贴板的所有权分配给当前打开剪贴板的窗口。
2>放置数据
HANDLE SetClipboardData(
UINT uFormat,
HANDLE hMem);
3>数据发送
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();
}
}
4>数据接受
void CClipboardDlg::OnBnClickedBtnRecv()
{
// 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);
GlobalUnlock(hClip);
SetDlgItemText(IDC_EDIT_RECV,pBuf);
CloseClipboard();
}
}
}
2.匿名管道
2.1创建管道和创建进程
匿名管道是一个未命名的、单向管道,通常用来在一个父进程和一个子进程之间传输数据。匿名管道只能实现本地机器上网络的通信,而不能实现跨网络的通信。
BOOL CreatePipe(//创建管道
PHANDLE hReadPipe, // read handle
PHANDLE hWritePipe, // write handle
LPSECURITY_ATTRIBUTES lpPipeAttributes, // security attributes
DWORD nSize // pipe size
);
CreateProcess( //创建进程
LPCWSTR lpszImageName,
LPCWSTR lpszCmdLine,
LPSECURITY_ATTRIBUTES lpsaProcess,
LPSECURITY_ATTRIBUTES lpsaThread,
BOOL fInheritHandles,
DWORD fdwCreate,
LPVOID lpvEnvironment,
LPWSTR lpszCurDir,
LPSTARTUPINFOW lpsiStartInfo,
LPPROCESS_INFORMATION lppiProcInfo);
2.2父进程的实现:
1)创建单文档类型MFC应用程序
2)创建菜单一个名为“匿名管道”子菜单,添加三个菜单项,并分别为他们添加命令函数,如下
命名相应函数:
void CParentView::OnPipeCreaate()
{
//TODO: Add your command handler code here
}
void CParentView::OnPipeRead()
{
//TODO: Add your command handler code here
}
void CParentView::OnPipeWrite()
{
//TODO: Add your command handler code here
}
3)为ParentView类:添加两个成员变量
private:
HANDLEhWrite;
HANDLEhRead;
并在构造和析构函数做如下操作: