Lesson17——进程间通信的四种方式
剪贴板
BOOL EmptyClipboard();
该函数清空剪切板并释放剪切板内数据的句柄。函数在之后会将剪切板的所有权指派给当前打开剪切板的窗口
HGLOBAL WINAPI GlobalAlloc(
__in UINT uFlags // 分配属性(方式)
__in SIZE_T dwBytes // 分配的字节数
);
该函数从堆中分配一定数目的字节数.Win32内存管理器并不提供相互分开的局部和全局堆.提供这个函数只是为了与16位的Windows相兼容.
LPVOID WINAPI GlobalLock(
__in HGLOBAL hMem
);
锁定内存中指定的内存块,并返回一个地址值,令其指向内存块的起始处。除非用 GlobalUnlock 函数将内存块解锁,否则地址会一直保持有效。
BOOL WINAPI GlobalUnlock(
__in HGLOBAL hMem
);
GlobalUnlock函数解除锁定的内存块,使指向该内存块的指针无效,GlobalLock锁定的内存,一定要用GlobalUnlock解锁
HANDLE SetClipboardData(
UINT uFormat,
HANDLE hMem
);
设置剪切板信息
HANDLE GetClipboardData(
UINT uFormat
);
获取剪切板信息
BOOL CloseClipboard();
关闭剪贴板,这使其他窗口能访问剪贴板
匿名管道
用于在父子进程中实现信息交流。首先添加两个HANDLE成员变量hRead和hWrite,
创建匿名管道前加入如下代码:
SECURITY_ATTRIBUTES sa;
sa.bInheritHandle=TRUE;
sa.lpSecurityDescriptor=NULL;
sa.nLength=sizeof(SECURITY_ATTRIBUTES);
CreatePipe(&hRead,&hWrite,&sa,0)
BOOL WINAPI CreatePipe(
__out PHANDLE hReadPipe,
__out PHANDLE hWritePipe,
__in LPSECURITY_ATTRIBUTES lpPipeAttributes,
__in DWORD nSize
);
创建匿名管道完成后加入如下代码:
STARTUPINFO sui;
PROCESS_INFORMATION pi;
ZeroMemory(&sui,sizeof(STARTUPINFO));
sui.cb=sizeof(STARTUPINFO);
sui.dwFlags=STARTF_USESTDHANDLES;
sui.hStdInput=hRead;
sui.hStdOutput=hWrite;
sui.hStdError=GetStdHandle(STD_ERROR_HANDLE);
CreateProcess("..//Child//Debug//Child.exe",NULL,NULL,NULL,TRUE,0,NULL,NULL,&sui,&pi)
BOOL WINAPI CreateProcess(
__in LPCTSTR lpApplicationName,
__in_out LPTSTR lpCommandLine,
__in LPSECURITY_ATTRIBUTES lpProcessAttributes,
__in LPSECURITY_ATTRIBUTES lpThreadAttributes,
__in BOOL bInheritHandles,
__in DWORD dwCreationFlags,
__in LPVOID lpEnvironment,
__in LPCTSTR lpCurrentDirectory,
__in LPSTARTUPINFO lpStartupInfo,
__out LPPROCESS_INFORMATION lpProcessInformation
);
在父进程中创建子进程,然后关闭子进程的进程和主线程的句柄
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
这样我们就创建的一个建立在父子进程之间的匿名管道,如果我们需要传递信息的话只需使用:
ReadFile(hRead,buf,100,&dwRead,NULL)
WriteFile(hWrite,buf,strlen(buf)+1,&dwWrite,NULL)
命名管道
n 命名管道是通过网络来完成进程间的通信,它屏蔽了底层的网络协议细节。我们在不了解网络协议的情况下,也可以利用命名管道来实现进程间的通信。
n 命名管道充分利用了Windows NT和Windows 2000内建的安全机制。
n 将命名管道作为一种网络编程方案时,它实际上建立了一个客户机/服务器通信体系,并在其中可靠地传输数据。
n 命名管道是围绕Windows文件系统设计的一种机制,采用“命名管道文件系统(Named Pipe File System,NPFS)”接口,因此,客户机和服务器可利用标准的Win32文件系统函数(例如:ReadFile和WriteFile)来进行数据的收发。
n 命名管道服务器和客户机的区别在于:服务器是唯一一个有权创建命名管道的进程,也只有它才能接受管道客户机的连接请求。而客户机只能同一个现成的命名管道服务器建立连接。
n 命名管道服务器只能在Windows NT或Windows 2000上创建,所以,我们无法在两台Windows 95或Windows 98计算机之间利用管道进行通信。不过,客户机可以是Windows 95或Windows 98计算机,与Windows NT或Windows 2000计算机进行连接通信。
n 命名管道提供了两种基本通信模式:字节模式和消息模式。在字节模式中,数据以一个连续的字节流的形式,在客户机和服务器之间流动。而在消息模式中,客户机和服务器则通过一系列不连续的数据单位,进行数据的收发,每次在管道上发出了一条消息后,它必须作为一条完整的消息读入。
服务器端
创建命名管道:
hPipe=CreateNamedPipe(".//pipe//MyPipe",
PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,0,1,1024,1024,0,NULL);
创建事件对象:
hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);
等待客户端连接:
OVERLAPPED ovlap;
ZeroMemory(&ovlap,sizeof(OVERLAPPED));
ovlap.hEvent=hEvent;
ConnectNamedPipe(hPipe,&ovlap)
WaitForSingleObject(hEvent,INFINITE)
关闭事件句柄:
CloseHandle(hEvent);
客户端:
等待可利用命名管道:
WaitNamedPipe(".//pipe//MyPipe",NMPWAIT_WAIT_FOREVER)
创建命名管道:
hPipe=CreateFile(".//pipe//MyPipe",GENERIC_READ | GENERIC_WRITE,
0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
服务器端和客户端管道建立好之后,数据的传递与匿名管道相同,它可以在任意两个进程间进行信息交流。
邮槽
n 邮槽是基于广播通信体系设计出来的,它采用无连接的不可靠的数据传输。
n 邮槽是一种单向通信机制,创建邮槽的服务器进程读取数据,打开邮槽的客户机进程写入数据。
n 为保证邮槽在各种Windows平台下都能够正常工作,我们传输消息的时候,应将消息的长度限制在424字节以下。
服务器端(接收数据)
HANDLE hMailslot;
hMailslot=CreateMailslot(".//mailslot//MyMailslot",0,MAILSLOT_WAIT_FOREVER,NULL);
ReadFile(hMailslot,buf,100,&dwRead,NULL)
CloseHandle(hMailslot);
客户端(发送数据)
HANDLE hMailslot;
hMailslot=CreateFile(".//mailslot//MyMailslot",GENERIC_WRITE,
FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
WriteFile(hMailslot,buf,strlen(buf)+1,&dwWrite,NULL)
CloseHandle(hMailslot)