我们对发送数据按钮进行响应:
void CCH_16_ClipboardDlg::OnBntSend()
{
// TODO: Add your control notification handler code here
//打开剪切板
if(!OpenClipboard())
{
MessageBox("打开剪切板失败");
return ;
}
//获取剪切板控制权,释放剪切板中之前的数据
if(!EmptyClipboard())
{
MessageBox("进入剪切板失败");
return ;
}
//获取编辑框中的文字
CString str;
GetDlgItemText(IDC_EDIT_SEND,str);
//内存对象,从全局堆分配
HGLOBAL hClip;
hClip = GlobalAlloc(GMEM_MOVEABLE, //
sizeof(str)+1); //大小
//获取内存对象的指针
char* pBuf;
pBuf = (char*)GlobalLock(hClip);
//完成数据的拷贝
strcpy(pBuf,str);
//减少引用计数,解锁
GlobalUnlock(hClip);
//向剪贴板中放入数据
SetClipboardData(CF_TEXT, //文本格式
hClip); //内存对象
//关闭剪切板,使其他进程可以获取剪切板
CloseClipboard();
}
void CCH_16_ClipboardDlg::OnBtnRecv()
{
// TODO: Add your control notification handler code here
if(!OpenClipboard())
{
MessageBox("无法打开剪切板");
return ;
}
//判断剪切板中的数据是否是指定格式
if(!IsClipboardFormatAvailable(CF_TEXT))
{
MessageBox("剪切板数据格式错误");
return ;
}
//获取剪切板内存对象
HANDLE hClip;
hClip = GetClipboardData(CF_TEXT);
//获取内存对象指针
char* pBuf = (char*)GlobalLock(hClip);
GlobalUnlock(hClip);
//设置文字
SetDlgItemText(IDC_EDIT_RECV,pBuf);
//关闭剪切板,使其他进程可以获取剪切板
CloseClipboard();
}
此时,在编辑框输入输入后,点击发送,然后点击接收,就能收到之前发送的数据了。
private:
HANDLE hWrite;
HANDLE hRead;
CCH_17_ParentView::CCH_17_ParentView()
{
// TODO: add construction code here
hRead = NULL;
hWrite = NULL;
}
CCH_17_ParentView::~CCH_17_ParentView()
{
if(hRead)
{
CloseHandle(hRead);
}
if(hWrite)
{
CloseHandle(hWrite);
}
}
void CCH_17_ParentView::OnPipeCreate()
{
// TODO: Add your command handler code here
//定义安全属性结构体
SECURITY_ATTRIBUTES sa;
//可以被继承
sa.bInheritHandle = TRUE;
//默认安全描述
sa.lpSecurityDescriptor = NULL;
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
//创建匿名管道
if(CreatePipe(&hRead, //读句柄
&hWrite, //写句柄
&sa, //安全属性
0)) //默认大小
{
MessageBox("创建匿名管道失败");
return ;
}
//新创建的进程的主窗口信息
STARTUPINFO sui;
ZeroMemory(&sui,sizeof(STARTUPINFO));
sui.cb = sizeof(STARTUPINFO);
sui.dwFlags = STARTF_USESTDHANDLES;
sui.hStdInput = hRead;
sui.hStdOutput = hWrite;
//获取标准输入句柄
sui.hStdError = GetStdHandle(STD_ERROR_HANDLE);
//新创建的进程和主线程信息,由函数填写
PROCESS_INFORMATION pi;
//创建子进程
if(!CreateProcess("..\\CH_17_Child\\Debug\\CH_17_Child.exe",//子进程名
NULL, //命令行参数为空
NULL, //新创建的进程使用默认安全级别
NULL, //新创建的主线程使用默认安全级别
TRUE, //子进程可以继承父进程的句柄
0, //无特殊创建标记
NULL, //新进程使用调用进程的环境块
NULL, //子进程和父进程具有相同的当前路径
&sui, //启动信息
&pi)) //新创建的进程和主线程信息
{
CloseHandle(hWrite);
hWrite = NULL;
CloseHandle(hRead);
hRead = NULL;
MessageBox("创建子进程失败");
return ;
}
else
{
//关闭句柄
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
}
程序其实不长,只是CreateProcess函数的参数很多。我们重点看一下最后两个:
typedef struct _STARTUPINFO {
DWORD cb;
LPTSTR lpReserved;
LPTSTR lpDesktop;
LPTSTR lpTitle;
DWORD dwX;
DWORD dwY;
DWORD dwXSize;
DWORD dwYSize;
DWORD dwXCountChars;
DWORD dwYCountChars;
DWORD dwFillAttribute;
DWORD dwFlags;
WORD wShowWindow;
WORD cbReserved2;
LPBYTE lpReserved2;
HANDLE hStdInput;
HANDLE hStdOutput;
HANDLE hStdError;
} STARTUPINFO, *LPSTARTUPINFO;
typedef struct _PROCESS_INFORMATION {
HANDLE hProcess;
HANDLE hThread;
DWORD dwProcessId;
DWORD dwThreadId;
} PROCESS_INFORMATION;
void CCH_17_ParentView::OnPipeRead()
{
// TODO: Add your command handler code here
char buf[200];
DWORD dwRead;
if(!ReadFile(hRead, //读句柄
buf, //缓冲区
100, //将要读取的大小
&dwRead,//实际读取的大小
NULL)) //非重叠
{
MessageBox("读取数据失败");
return ;
}
MessageBox(buf);
}
void CCH_17_ParentView::OnPipeWrite()
{
// TODO: Add your command handler code here
char buf[] = "父进程发送的数据";
DWORD dwWrite;
if(!WriteFile(hWrite, //句柄
buf, //缓冲区
strlen(buf)+1,//将要读取饿大小
&dwWrite, //实际大小
NULL)) //非重叠
{
MessageBox("写入数据失败");
return ;
}
}
使用的是之前就是用过的ReadFile和WriteFile实现的,这里就不再多说了。
void CCH_17_ChildView::OnInitialUpdate()
{
CView::OnInitialUpdate();
// TODO: Add your specialized code here and/or call the base class
hRead = GetStdHandle(STD_INPUT_HANDLE);
hWrite = GetStdHandle(STD_OUTPUT_HANDLE);
}
void CCH_17_ChildView::OnPipeWrite()
{
// TODO: Add your command handler code here
char buf[] = "匿名管道客户端数据";
DWORD dwWrite;
if(!WriteFile(hWrite,buf,strlen(buf)+1,&dwWrite,NULL))
{
MessageBox("写入数据失败");
return ;
}
}
void CCH_17_ChildView::OnInitialUpdate()
{
CView::OnInitialUpdate();
// TODO: Add your specialized code here and/or call the base class
hRead = GetStdHandle(STD_INPUT_HANDLE);
hWrite = GetStdHandle(STD_OUTPUT_HANDLE);
}
void CCH_17_NamedPipeSrvView::OnPipeCreate()
{
// TODO: Add your command handler code here
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结构
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 ;
}
}
void CCH_17_NamedPipeSrvView::OnPipeRead()
{
// TODO: Add your command handler code here
char buf[100];
DWORD dwRead;
if(!ReadFile(hPipe,buf,100,&dwRead,NULL))
{
MessageBox("读取数据失败");
return ;
}
MessageBox(buf);
}
void CCH_17_NamedPipeSrvView::OnPipeWrite()
{
// TODO: Add your command handler code here
char buf[] = "命名管道服务器数据";
DWORD dwWrite;
if(!WriteFile(hPipe,buf,strlen(buf)+1,&dwWrite,NULL))
{
MessageBox("服务器写入数据失败");
return ;
}
}
void CCH_17_NamedPipeCltView::OnPipeConnect()
{
// TODO: Add your command handler code here
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 ;
}
}
void CCH_17_NamedPipeCltView::OnPipeRead()
{
// TODO: Add your command handler code here
char buf[100];
DWORD dwRead;
if(!ReadFile(hPipe,buf,100,&dwRead,NULL))
{
MessageBox("读取数据失败");
return ;
}
MessageBox(buf);
}
void CCH_17_NamedPipeCltView::OnPipeWrite()
{
// TODO: Add your command handler code here
char buf[] = "命名管道客户端数据";
DWORD dwWrite;
if(!WriteFile(hPipe,buf,strlen(buf)+1,&dwWrite,NULL))
{
MessageBox("服务器写入数据失败");
return ;
}
}
void CCH_17_MailslotSrvView::OnMailslotRecv()
{
// TODO: Add your command handler code here
HANDLE hMaileslot;
hMaileslot = CreateMailslot("\\\\.\\mailslot\\MyMailslot", //邮槽名
0, //任意长度的消息大小
MAILSLOT_WAIT_FOREVER, //一直等待
NULL); //默认安全属性
if(INVALID_HANDLE_VALUE == hMaileslot)
{
MessageBox("创建油槽失败");
return ;
}
char buf[200];
DWORD dwRead;
if(!ReadFile(hMaileslot,buf,200,&dwRead,NULL))
{
MessageBox("读取数据失败");
CloseHandle(hMaileslot);
return ;
}
MessageBox(buf);
CloseHandle(hMaileslot);
}
注意,服务器端只接收数据。
void CCH_17_MailslotCltView::OnMailslotSend()
{
// TODO: Add your command handler code here
HANDLE hMailslot;
hMailslot = CreateFile("\\\\.\\mailslot\\MyMailslot", //邮槽名
GENERIC_WRITE, //写数据
FILE_SHARE_WRITE, //写共享
NULL, //默认安全属性
OPEN_EXISTING, //打开已存在的邮槽
FILE_ATTRIBUTE_NORMAL, //常规属性
NULL); //
if(INVALID_HANDLE_VALUE == hMailslot)
{
MessageBox("打开邮槽失败");
return ;
}
char buf[] = "客户端发送数据";
DWORD dwWrite;
if(!WriteFile(hMailslot,buf,sizeof(buf),&dwWrite,NULL))
{
MessageBox("写入数据失败");
CloseHandle(hMailslot);
return ;
}
CloseHandle(hMailslot);
}