进程间的通信:
剪贴板
匿名管道
命名管道
邮遭
剪贴板:
打开剪贴板OpenClipBoard(),如果打开成功就返回非0值,否则返回0,如果某个程序已经打开了剪
贴板,则其他应用程序将不能修改剪贴板,直到前者调用了CloseClipboard函数。并且只有调用
EmptyClipboard函数之后,打开剪贴板的当前窗口才拥有剪贴板。SetClipboardData向剪贴板放置数据
。
void CClipboardDlg::OnBnClickedBtnSend()
{
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::OnBnClickedBtnRecv()
{
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();
}
}
匿名管道:
匿名管道是一个未命名的、单项管道,通常用来在一个父进程之间传输数据。匿名管道只能实现本
地机器上两个进程间的通信,而不能实现跨网络通信
BOOL CreatePipe(
PHANDLE hReadPipe,
PHANDLE hWritePipe,
LPSECURITY_ATTRIBUTES lpPipeAttributes,//不能为空,匿名管道只能在父进程和子进程之间进行通信
。子进程如果想要获取匿名管道只能从父进程继承而来。
DWORD nSize
);
BOOL CreateProcess(
LPCTSTR lpApplicationName,//应用程序路径和名称
LPTSTR lpCommandLine,//命令行参数
LPSECURITY_ATTRIBUTES lpProcessAttributes,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles,
DWORD dwCreationFlags, //创建标志CREATE_NO_WINDOW
LPVOID lpEnvironment,
LPCTSTR lpCurrentDirectory,
LPSTARTUPINFO lpStartupInfo,//新进程主窗口如何显示
LPPROCESS_INFOMATION lpProcessInformation
);
实现步骤:
1.创建匿名管道
2.创建子进程
3.实现读取数据和写入数据函数
4.实现子进程
5.获得管道的读取和写入句柄
6.实现读写数据函数
总结:创建管道的时候会返回读句柄和写句柄,父继承通过调用ReadFile,并指定读句柄读取数据,通
过WriteFile,并指定写句柄写入数据。由于子进程继承自父进程,所以可以通过GetStdHandle
(STD_INPUT_HANDLE)和GetStdHandle(STD_OUTPUT_HANDLE)获取句柄,获取的最佳时机是在窗口刚刚创建
完毕时,即OnInitialUpdate()虚函数中,然后通过ReadFile,WriteFile向管道读写数据。
void CParentView::OnPipeCreate()
{
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));
sui.cb = sizeof( STARTUPINFO);
sui.dwFlags = STARTF_USESTDHANDLES;
sui.hStdInput = hRead;
sui.hStdOutput = hWrite;
sui.hStdError = GetStdHandle(STARTF_USESTDHANDLES);
if( !CreateProcess("..\\TEST\\Debug\\TEST.exe", NULL, NULL, NULL, TRUE,
CREATE_NO_WINDOW, NULL, NULL, &sui, &pi))
{
CloseHandle(hRead);
CloseHandle(hWrite);
hRead = NULL;
hWrite = NULL;
MessageBox("创建子进程失败!");
return;
}
else
{
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
}
void CParentView::OnPipeRead()
{
char buf[100];
DWORD dwRead;
if( !ReadFile(hRead, buf, 100, &dwRead, NULL))
{
MessageBox("读取数据失败");
return ;
}
MessageBox(buf);
}
void CParentView::OnPipeWrite()
{
char buf[] = "bolg.csdn.com/lalor";
DWORD dwWrite;
if( !WriteFile(hWrite, buf, strlen(buf) + 1, &dwWrite, NULL) )
{
MessageBox("写入数据失败");
return;
}
}
命名管道:
命名管道不仅可以在本机上实现两个进程间的通信,还可以跨网络实现两个进程间的通信。
HANDLE CreateNamePipe(
LPCTSTR lpName,"\\.\pipe\\pipename"
DOWRD dwOpenMode,//指定访问模式,重叠方式等
DWORD dwPipeMode,
DWORD nMaxInstances,//可创建的实例的最大数目
DWORD nOutBufferSize,
DWORD nInBufferSize,
DWORD nDefaultTimeOut,
LPSECURITY_ATTRIBUTES lpSecurityAttributes
);
实现步骤:
1.创建命名管道
2.创建人工重置事件
3.等待连接
4.实现读取数据和写入数据函数
5.客户端连接管道
6.实现读取数据和写入数据函数
void CNamedPipeSrvView::OnPipeCreate()
{
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(sa);
sa.bInheritHandle = TRUE;
sa.lpSecurityDescriptor = &sa;
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()
{
char buf[100];
DWORD dwRead;
if( !ReadFile(hPipe, buf, 100, &dwRead, NULL))
{
MessageBox("读取数据失败");
return;
}
MessageBox(buf);
}
void CNamedPipeSrvView::OnPipeWrite()
{
char buf[] = "http://www.sunxin.org";
DWORD dwWrite;
if( !WriteFile(hPipe, buf, strlen(buf) + 1 , &dwWrite, NULL))
{
MessageBox("写入数据失败");
return;
}
}
客户端连接代码:
void CNamedPipeCltView::OnPipeConnect()
{
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;
}
}
邮遭是基于广播通信体系设计出来的,它采用无连接的不可靠的数据传输。油槽是一种单向通信机
制,创建邮遭的服务器进程读取数据,打开油槽的客户机进程写入数据。
HANDLE CreateMailslot(
LPCTSTR lpName, "\\.\mailsolt\[path]name"
DWORD nMaxMessageSize,//可以写入邮遭单一消息的最大尺寸
DWORD lReadTimeout,//读取操作的超时时间
LPSECURITY_ATTRIBUTES lpSecurityAttributes
);
服务器端:
void CMailSoltSrvView::OnMailslotRecv()
{
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);
}
客户端:
void CMailslotCltView::OnMailslotSend()
{
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[] = "Hello, I'am lalor";
DWORD dwWrite;
if ( ! WriteFile(hMailslot, buf, strlen(buf) + 1, &dwWrite, NULL))
{
MessageBox("写入数据失败");
CloseHandle(hMailslot);
return;
}
CloseHandle(hMailslot);
}
VC深入详解之第十七章进程间的通信笔记
最新推荐文章于 2020-07-27 17:41:49 发布
本文详细介绍了进程间通信的三种方式:剪贴板、匿名管道和命名管道,以及邮槽的使用方法。从原理到实现步骤,逐一阐述,旨在帮助开发者理解和应用这些通信机制。
8547

被折叠的 条评论
为什么被折叠?



