当前位置:文档之家› 进程间通信的四种方式

进程间通信的四种方式

一、剪贴板1、基础知识剪贴板实际上是系统维护管理的一块内存区域,当在一个进程中复制数据时,是将这个数据放到该块内存区域中,当在另一个进程中粘贴数据时,是从该内存区域中取出数据。

2、函数说明:(1)、BOOL OpenClipboard( )CWnd类的OpenClipboard函数用于打开剪贴板。

若打开剪贴板成功,则返回非0值。

若其他程序或当前窗口已经打开了剪贴板,则该函数返回0值,表示打开失败。

若某个程序已经打开了剪贴板,则其他应用程序将不能修改剪贴板,直到前者调用了CloseClipboard函数。

(2)、BOOL EmptyClipboard(void)EmptyClipboard函数将清空剪贴板,并释放剪贴板中数据的句柄,然后将剪贴板的所有权分配给当前打开剪贴板的窗口。

(3)、HANDLE SetClipboardData(UINT uFormat, HANDLE hMem)SetClipboardData函数是以指定的剪贴板格式向剪贴板上放置数据。

uFormat指定剪贴板格式,这个格式可以是已注册的格式,或是任一种标准的剪贴板格式。

CF_TEXT表示文本格式,表示每行数据以回车换行(0x0a0x0d)终止,空字符作为数据的结尾。

hMem指定具有指定格式的数据的句柄。

hMem参数可以是NULL,指示采用延迟提交技术,则该程序必须处理WM_RENDERFORMA T和WM_RENDERALLFORMATS消息。

应用程序在调用SetClipboardData函数之后,就拥有了hMem参数所标识的数据对象,该应用程序可以读取该数据对象,但在应用程序调用CloseClipboard函数之前,它不能释放该对象的句柄,或者锁定这个句柄。

若hMem标识了一个内存对象,那么这个对象必须是利用GMEM_MOVEABLE标志调用GlobalAlloc函数为其分配内存。

注意:调用SetClipboardData函数的程序必须是剪贴板的拥有者,且在这之前已经打开了剪贴板。

延迟提交技术:当一个提供数据的进程创建了剪贴板数据之后,直到其他进程获取剪贴板数据之前,这些数据都要占据内存空间。

若在剪贴板上放置的数据过大,就会浪费内存空间,降低对资源的利用率。

为了避免这种浪费,就可以采用延迟提交计数,也就是由数据提供进程先提供一个指定格式的空剪贴板数据块,即把SetClipboardData函数的hMem参数设置为NULL。

当需要获取数据的进程想要从剪贴板上得到数据时,操作系统会向数据提供进程发送WM_RENDERFORMA T消息,而数据提供进程可以响应这个消息,并在此消息的响应函数中,再一次调用SetClipboardData函数,将实际的数据放到剪贴板上。

当再次调用SetClipboardData函数时,就不再需要调用OpenClipboard函数,也不再需要调用EmptyClipboard函数。

也就是说,为了提高资源利用率,避免浪费内存空间,可以采用延迟提交技术。

第一次调用SetClipboardData函数时,将其hMem参数设置为NULL,在剪贴板上以指定的剪贴板格式放置一个空剪贴板数据块。

然后直到有其他进程需要数据或自身进程需要终止运行时再次调用SetClipboardData函数,这时才真正提交数据。

(4)、HGLOBAL GlobalAlloc( UINT uFlags,SIZE_T dwBytes);GlobalAlloc函数从堆上分配指定数目的字节。

uFlags是一个标记,用来指定分配内存的方式,uFlags为0,则该标记就是默认的GMEM_FIXED。

dwBytes指定分配的字节数。

存中从来不被移动,但可在一个默认堆中被移动。

创建一个进程时,系统为应用程序分配一块默认堆。

返回值是一块内存对象句柄,若想将这个句柄转换为一个指针,可以使用GlobalLock函数。

这个标志不能和GMEM_FIXED标志一起使用。

GMEM_ZEROINIT 初始化内存的内容为0GPTR GMEM_FIXED和GMEM_ZEROINIT的组合(5)、LPVOID GlobalLock(HGLOBAL hMem);GlobalLock函数是对全局内存对象加锁,然后返回该对象内存块第一个字节的指针。

hMem 指一个全局内存对象句柄。

每个内存对象的内部数据结构中都包含了一个初始值为0的锁计数,对于可移动的内存对象来说,GlobalLock函数将其锁计数加1,而GlobalUnlock函数将锁计数减1。

被锁定的内存对象的内存块将保持锁定,直到它的锁计数为0,这时,该内存块才能被移动,或者被废弃。

另外,已被加锁的内存不能被移动,或者被废弃,除非调用了GlobalRealloc函数重新分配了该内存对象。

对于一个进程来说,每一次调用GlobalLock函数后,最后一定要记住调用GlobalUnlock函数。

使用GMEM_FIXED标志分配的内存对象其锁计数总是0。

GMEM_FIXED与GMEM_MOVEABLE标志的区别:若指定的是前者,那么GlobalAlloc函数返回的句柄值就是分配的内存地址;若指定的是后者,那么GlobalAlloc 函数返回的不是实际内存的地址,而是指向该进程中句柄表条目的指针,该条目中包含有实际分配的内存指针。

若一个函数的返回值为HGLOBAL类型,那么我们应该假定它的内存是采用GMEM_MOVEABLE标志来分配的,这就意味值必须调用GlobalLock函数对该全局内存对象加锁,并且返回该内存的地址。

若一个函数的参数类型为HGLOBAL,我们就应该用GMEM_MOVEABLE标志调用GlobalAlloc函数来生成这个参数值。

3、实例讲解,利用剪贴板实现通信(1)、新建一个基于对话框的MFC程序Clipboard,设计ID为IDD_CLIPBOARD_DIALOG 的对话框资源如下:(2)、为Send按钮添加单击命令响应函数,将发送编辑框中的内容发送到剪贴板:void CClipboardDlg::OnBtnSend(){if(OpenClipboard()){//打开剪贴板成功CString str;//用于保存发送编辑框中的数据HANDLE hClip;//用于保存GlobalAlloc函数分配的内存对象的句柄char *pBuf;//用于保存调用GlobalLock函数后返回的内存地址EmptyClipboard();//清空剪贴板,并获得剪贴板所有权GetDlgItemText(IDC_EDIT_SEND,str);//将发生编辑框中的数据保存到strhClip=GlobalAlloc(GMEM_MOVEABLE,str.GetLength()+1);//分配内存对象,若设定的是文本数据,那么该数据是以空字符结尾,所以多分配一个字节pBuf=(char*)GlobalLock(hClip);//对内存对象加锁,将句柄转换为指针strcpy(pBuf,str);//将str中的数据复制到pBuf指向的内存中GlobalUnlock(hClip);//对内存块解锁SetClipboardData(CF_TEXT,hClip);\\向剪贴板上放置数据CloseClipboard();//关闭剪贴板}}注意:在把数据放置到剪贴板之后,一定要记得调用CloseClipboard函数关闭剪贴板,否则其他进程将无法打开剪贴板。

(3)、为Recv按钮添加单击命令响应函数,从剪贴板上取出数据显示到接受编辑框中:void CClipboardDlg::OnBtnRecv(){if (OpenClipboard()){//打开剪贴板成功if (IsClipboardFormatAvailable(CF_TEXT)){//若剪贴板中的数据是CF_TEXT格式的数据HANDLE hClip;char *pBuf;hClip=GetClipboardData(CF_TEXT);//返回CF_TEXT格式存在的剪贴板对象的句柄pBuf=(char*)GlobalLock(hClip);GlobalUnlock(hClip);SetDlgItemText(IDC_EDIT_RECV,pBuf);}CloseClipboard();}}二、匿名管道1、基础知识匿名管道是一个未命名的单向管道,通常用来在一个父进程和一个子进程之间传输数据。

匿名管道只能实现本地机器上两个父子进程间的通信,而不能实现跨网络的通信。

另外,利用匿名管道还可以实现同一个进程内数据的读取和写入。

2、函数说明(1)、BOOL CreatePipe(PHANDLE hReadPipe,PHANDLE hWritePipe,LPSECURITY_ATTRIBUTES lpPipeAttributes,DWORD nSize)CreatePipe创建一个匿名管道。

hReadPipe返回管道的读取句柄,hWritePipe返回管道的写入句柄。

lpPipeAttributes指向SECURITY_ATTRIBUTES结构体的指针,检测返回的句柄是否能被子进程继承,若此参数为NULL,则句柄不能被继承。

nSize指定管道的缓冲区大小,该大小仅仅是一个建议值,系统将使用该值计算一个适当的缓冲区大小,若此参数为0,系统则使用默认的缓冲区大小。

(2)、typedef struct _SECURITY_A TTRIBUTES {DWORD nLength;LPVOID lpSecurityDescriptor;BOOL bInheritHandle;} SECURITY_ATTRIBUTES, *PSECURITY_A TTRIBUTES;SECURITY_ATTRIBUTES结构体的nLength指定该结构体的大小。

lpSecurityDescriptor指向安全描述符的指针,若该参数为NULL,则系统为创建的匿名管道赋予默认的安全描述符。

bInheritHandle指定所返回的句柄是否能被一个新的进程所继承,若该参数设为TRUE,则返回的句柄能被新进程继承。

(3)、BOOL CreateProcess(LPCTSTR lpApplicationName,LPTSTR lpCommandLine,LPSECURITY_ATTRIBUTES lpProcessAttributes,LPSECURITY_ATTRIBUTES lpThreadAttributes,BOOL bInheritHandles,DWORD dwCreationFlags,LPVOID lpEnvironment,LPCTSTR lpCurrentDirectory,LPSTARTUPINFO lpStartupInfo,LPPROCESS_INFORMATION lpProcessInformation );CreateProcess创建一个进程。

相关主题