有四种方法
1.
剪贴板
a.
创建个
ClipBoard
的对话框应用程序,加两 EditBox和两个Button 发送接收。
b.
具体代码:
发送端代码:
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();
}
接收端代码:
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.
匿名管道:只能在父子进程之间进行通信
a.
先建一个
Parent
的单文档应用程序,增加“创建管道”“读取数据”“写入数据”三个菜单
b.
增加成员变量
HANDLE
类型的
hRead,hWrite,初始化变量,并在析构函数中释放句柄
c.
响应菜单代码:
void CParentView::OnPipeCreate()
菜单“创建管道”代码
{
// TOD 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;
PROCESS_INFORMATION pi;
ZeroMemory(&sui,sizeof(STARTUPINFO));
将数据清 0!
sui.cb=sizeof(STARTUPINFO);
sui.dwFlags=STARTF_USESTDHANDLES;
sui.hStdInput=hRead;
sui.hStdOutput=hWrite;
sui.hStdError=GetStdHandle(STD_ERROR_HANDLE);
if(!CreateProcess("..\\Child\\Debug\\Child.exe",NULL,NULL,NULL,
TRUE,0,NULL,NULL,&sui,&pi))
创建子进程
{
CloseHandle(hRead);
CloseHandle(hWrite);
关闭句柄,将内核对象的使用计数减少 1,这样当操作系统发现内核对象的使用计数为 0时,将清除内核对象。
hRead=NULL;
hWrite=NULL;
MessageBox("
创建子进程失败! ");
return;
}
else
{
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
}void CParentView::OnPipeRead()
菜单“读取数据”代码
{
// TOD Add your command handler code here
char buf[100];
DWORD dwRead;
if(!ReadFile(hRead,buf,100,&dwRead,NULL))
{
MessageBox("
读取数据失败! ");
return;
}
MessageBox(buf);
}void CParentView::OnPipeWrite()
菜单“写入数据”代码
{
// TOD Add your command handler code here
char buf[]="http://www.sunxin.org";
DWORD dwWrite;
if(!WriteFile(hWrite,buf,strlen(buf)+1,&dwWrite,NULL))
{
MessageBox("
写入数据失败! ");
return;
}
}
d.
再建一个 Child的单文档,在View中增加两个成员 hRead和hWrite. 在OnInitialUpdate()中得到句柄的值。
void CChildView::OnInitialUpdate()
{
CView::OnInitialUpdate();
// TOD Add your specialized code here and/or call the base class
hRead=GetStdHandle(STD_INPUT_HANDLE);
注意这句代码!
hWrite=GetStdHandle(STD_OUTPUT_HANDLE);
} e.
加菜单“读取数据”“写入数据”其代码如下:
void CChildView::OnPipeRead()
{
// TOD Add your command handler code here
char buf[100];
DWORD dwRead;
if(!ReadFile(hRead,buf,100,&dwRead,NULL))
{
MessageBox("
读取数据失败! ");
return;
}
MessageBox(buf);
}void CChildView::OnPipeWrite()
{
// TOD Add your command handler code here
char buf[]="
匿名管道测试程序 ";
DWORD dwWrite;
if(!WriteFile(hWrite,buf,strlen(buf)+1,&dwWrite,NULL))
{
MessageBox("
写入数据失败! ");
return;
}
}
3.
命名管道:还可以跨网络通信,服务器只能在
win2000和NT 下运行!而客户端可以在 95下运行。关键函数CreateNamedPipe
a.
先建一个
NamedPipeSRV
单文档应用程序,加菜单“创建管道”“读取数据”“写入数据”
b.
在
View
中增加Handle变量 hPipe,注意在析构函数中释放它!
c.
响应菜单,创建命名管道
void CNamedPipeSrvView::OnPipeCreate()
{
// TOD 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 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()
{
// TOD Add your command handler code here
char buf[100];
DWORD dwRead;
if(!ReadFile(hPipe,buf,100,&dwRead,NULL))
{
MessageBox("
读取数据失败! ");
return;
}
MessageBox(buf);
}void CNamedPipeSrvView::OnPipeWrite()
{
// TOD Add your command handler code here
char buf[]="http://www.sunxin.org";
DWORD dwWrite;
if(!WriteFile(hPipe,buf,strlen(buf)+1,&dwWrite,NULL))
{
MessageBox("
写入数据失败! ");
return;
}
} d.
再建一个 NamedPipeCLT单文档工程,加菜单“连接管道”“读取数据”“写入数据”,当然别忘记成员变量 hPipe的定义和初始化
e.
响应菜单代码
void CNamedPipeCltView::OnPipeConnect()
连接管道
{
// TOD 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 CNamedPipeCltView::OnPipeRead()
读取数据
{
// TOD Add your command handler code here
char buf[100];
DWORD dwRead;
if(!ReadFile(hPipe,buf,100,&dwRead,NULL))
{
MessageBox("
读取数据失败! ");
return;
}
MessageBox(buf);
}void CNamedPipeCltView::OnPipeWrite()
写入数据
{
// TOD Add your command handler code here
char buf[]="
命名管道测试程序 ";
DWORD dwWrite;
if(!WriteFile(hPipe,buf,strlen(buf)+1,&dwWrite,NULL))
{
MessageBox("
写入数据失败! ");
return;
}
}
4.
邮槽,使用时应将消息长度限制在
424字节以下,关键函数CreateMailSlot()
a.
先建一个
MailSlotSRV
工程,加菜单“接收数据”
b.
消息响应代码:
void CMailslotSrvView::OnMailslotRecv()
菜单“接收数据”的代码
{
// TOD Add your command handler code here
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);
}
c.
加工程MailSlotCLT,加菜单“发送数据”
d.
加消息响应,添加代码,客户端也比较简单。
void CMailslotCltView::OnMailslotSend()
菜单“发送数据”的代码
{
// TOD Add your command handler code here
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[]="http://www.sunxin.org";
DWORD dwWrite;
if(!WriteFile(hMailslot,buf,strlen(buf)+1,&dwWrite,NULL))
{
MessageBox("
写入数据失败! ");
CloseHandle(hMailslot);
return;
}
CloseHandle(hMailslot);
}5.
以上
4
种方法各有优缺点:剪贴板比较简单。邮槽是基于广播的,可以一对多发送。但只能一个发送,一个接收,要想同时发送接收,须写两次代码。
命名管道和邮槽可以进行网络通信。