一、剪贴板
1、数据发送
BOOL OpenClipboard(); 打开剪贴板。
向剪贴板中放置数据。
HANDLE SetClipboardData(UINT uFormat,HANDLE hMem);
参数: uFormat: 指定剪贴板格式,这个格式可以是已注册的格式,
或者是任一种标志的剪贴板格式。
hMem: 具有指定格式的数据的句柄。可以是NULL,指示
调用窗口直到有对剪贴板数据的请求时,才提供
指定剪贴板的数据。
HGLOBAL GlobalAlloc(UINT uFlags, SIZE_T dwBytes);
参数:uFlags: 指定分配内存的方式。
dwBytes: 指定分配的字节数。
LPVOID GlobalLock(HGLOBAL hMem); 给全局内存对象加锁。
GlobalUnLock 对全局
内存对象解锁。
已被加锁的内存不能被移动,或者被废除,废除调用了GlobalRealloc函数
重新分配了该内存对象。
发送数据例子:
if (OpenClipboard()) 打开剪贴板
{
CString str; 保存发送的数据。
HANDLE hClip; 保存调用GlobalAlloc函数后分配的内存对象的句柄
char *pBuf; 保存调用GlobalLock函数后返回的内存地址
EmptyClipboard(); 清空剪贴板上的数据。
str="aaaaaaa";
hClip=GlobalAlloc(GMEM_MOVEABLE,str.GetLength()+1);
pBuf=(char*)GlobalLock(hClip);
strcpy(pBuf,str);
GlobalUnlock(hClip);
SetClipboardData(CF_TEXT,hClip);
CloseClipBoard(); 关闭剪贴板。
}
在数据放置到剪贴板之后,一定要记得调用CloseClipBoard函数关闭剪贴板,
否则其他进程将无法打开剪贴板。
2、接收数据
if(OpenClipoard())
{
if(IsClipboardFormatAvailable(CF_TEXT)) 检查剪贴板中是否是我们
{ 想要的数据格式。
HANDLE hClip;
char *pBuf;
hClip=GetClipBoardData(CF_TEXT); 从剪贴板上获得指定格式的数据。
pBuf=(char*)GlobalLock(hClip); 获得数据的内存首地址。
GlobalUnlock(hClip);
}
CloseClipboard();
}
知识点: 当一个提供数据的进程创建了剪贴板数据之后,直到其他进程获取
剪贴板数据之前,这些数据都要占据内存空间。人工在剪贴板上放
置数据过大,就会浪费内存空间,降低对资源的利用率。为了避免
这种浪费,九可以采用延迟提交技术,也九是有数据提供先提供一
个指定格式的空剪贴板数据库,即把SetClipboardData函数的hMen
参数设置为NULL。当需要获取数据的进程想要从剪贴板上得到数据时,
操作系统会想数据提供者发送WM_RENDERFORMAT消息,而数据提供进
程可以响应这个消息,并在此消磁的响应函数中,再一次调用
SetClipboardData函数,将实际的数据放到剪贴板上,当再次调用
SetClipboardData函数时,就不再需要调用OpenClipboard函数,
也不再需要调用EmptyClipboard函数。也就是说,为了提高资源利
用率,避免浪费内存空间,可以采用延迟提交技术。第一次调用
SetClipboardData函数时,将其hMem参数设置为NULL,在剪贴板
上以指定的剪贴板格式放置一个空剪贴板数据块。然后直到有其他
进程需要数据或者自身进程需要终止运行时再次调用SetClipboardData
函数,这时才真正提交数据。
二、匿名管道
1、基础知识
匿名管道是ygie未命名的,单向管道,通常用来在一个父进程和一个子进程之间
传输数据。匿名管道只能实现本地机器上两个进程间的通信,而不能实现跨网
络的通信。
BOOL CreatePipe(PHANDLE hReadPipe,PHANDLE hWritePipe,
LPSECURITY_ATTRIBUTES lpPipeAttibutes,DWORD nSize);
参数:hReadPipe和 hWritePipe: 这两个参数都是out类型,即作为返回值来使用。
前者返回管道的读取句柄,后者接收管道的写入
句柄。
lpPipeAttibutes: 一个指向SECURITY_ATTRIBUTES结构体的指针,
检测返回的句柄是否能被子进程继承。
nSize: 指定管道的缓冲区大小,该大小仅仅是一个
建议值,系统将使用这个值来计算一个适当
的缓冲区大小,人工此参数是0,系统则使用
默认的缓冲区大小。
2、进程的创建
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);
参数: lpApplicationName: 一个指向NULL终止的字符串,用来指定可执行程序
的名称,是要运行程序的路径。
lpCommandLine: 一个指向NULL终止的字符串,用来指定传递给新进
程的命令行字符串。我们可以在
lpApplicationName参数中传递可执行文件的名称,
在lpCommandLine参数中传递命令行的参数。
lpProcessAttributes和lpThreadAttributes:
系统将为新进程创建一个进程内核对象和一个线程
内核对象,后者用于进程的主线程。
bINheritHandles: 该参数用来指定父进程随后创建的子进程是否能够
继承父进程的对象句柄。
dwCreationFlags: 指定控件优先级类和进程创建的附加标记。
lpEnvironment: 一个指向环境块的指针,如果此参数是NULL,那么
新进程使用调用进程的环境。
lpCurrentDirectory:一个指向空终止的字符串,用来指定子进程当前的
路径,这个字符串必须是一个完整的路径名。
lpStartupInfo: 一个指向STARTUPINFO结构体的指针,用来指定新
进程的主窗口将如何显式。
lpProcessInformation:返回值,是一个指向PROCESS_INFORMATION结构
体的指针,用来接收关于新进程的标识信息。
3、父进程的实现
private:
HANDLE hWrite;
HANDLE hRead;
hRead=NULL;
hWrite=NULL;
/**************************创建匿名管道******************************/
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(STD_ERROR_HANDLE);
if(!CreateProcess("..\\child\\debug\\child.exe",NULL,NULL,NULL,
TRUE,0,NULL,NULL,&sui,&pi))
{
CloseHandle(hRead);
CloseHandle(hWrite);
hRead=NULL;
hWrite=NULL;
MessageBox("创建子进程失败!");
return;
}
else
{
CloseHandle(pi.hProcess); 一定不能丢,为的是内核计数器减1.
CloseHandle(pi.hThread);
}
/*********************子进程结束************************************/
/********************管道读数据************************************/
char buf[100]; 存放读取的数据
DWORD dwRead; 保存实际读取的字节数。
if(!ReadFile(hRead,buf,100,&dwRead,NULL))
{
MessageBox("读取数据失败!");
return;
}
MessageBox(buf);
/*****************管道读取结束**********************************/
/******************写入数据*************************************/
char buf[]="http://www.sunxin.org"; //用于写入的数据
DWORD dwWrite; 写入数据的字节数。
if(!WriteFile(hWrite,buf,strlen(buf)+1,&dwWrite,NULL))
{
MessageBox("写入数据失败!");
return;
}
/*****************写入数据结束*******************************/
if(hRead)
CloseHandle(hRead);
if(hWrite)
CloseHandle(hWrite);
4、子进程的实现
private:
HANDLE hWrite;
HANDLE hRead;
hRead=NULL;
hWrite=NULL;
/****************获取管道的读取和写入句柄************************/
hRead=GetStdHandle(STD_INPUT_HANDLE);
hWrite=GetStdHandle(STD_OUTPUT_HANDLE);
/****************获取管道的读取和写入句柄结束********************/
/******************管道读数据************************************/
char buf[100]; 存放读取的数据
DWORD dwRead; 保存实际读取的字节数。
if(!ReadFile(hRead,buf,100,&dwRead,NULL))
{
MessageBox("读取数据失败!");
return;
}
MessageBox(buf);
/*****************管道读取结束******************************/
/*****************写入数据*******************************/
char buf[]="http://www.sunxin.org"; //用于写入的数据
DWORD dwWrite; 写入数据的字节数。
if(!WriteFile(hWrite,buf,strlen(buf)+1,&dwWrite,NULL))
{
MessageBox("写入数据失败!");
return;
}
/********************写入数据结束*************************/
if(hRead)
CloseHandle(hRead);
if(hWrite)
CloseHandle(hWrite);
注意: 匿名管道必须是父子进程间通信。
匿名管道也可以是同一个进程间读写数据。
三、命名管道
1、基础知识
命名管道通过网络来完成进程间的通信,它屏蔽了底层的网络协议细节。
命名管道不仅可以在本机子上实现两个进程间的通信,还可以跨网络实现
两个进程间的通信。对同一个命名管道的实例来说,在某一时刻,它只能
和一个客户端进行通信。
HANDLE CreateNamedPipe(
LPCTSTR lpName,
DWORD dwOpenMode,
DWORD dwPipeMode,
DWORD nMaxInstances,
DWORD nOutBufferSize,
DWORD nInBufferSize,
DWORD nDefaultTimeOut,
LPSECURITY_ATTRIBUTES lpSecurityAttributes);
参数:lpName: 指向空终止的字符串,该字符串的格式必须是:
"\\.\pipe\pipename".其中该字符串开始是两个
连续的反斜杠,其后的圆点标识是本地机器,如果
想要与远程的服务器建立连接,那么这个圆点位置
处应指定这个远程服务器的名称。接下来是"pipe"
这个固定的字符串,也就是说这个字符串的内容不
能修改,但其大小写是无所谓的。最后是创建的命
名管道的名称。
dwOpenMode:指定管道的访问方式,重叠方式,写直通方式,
还是管道句柄的安全访问方式。
dwPipeMode:指定管道句柄的类型,读取和等待方式。
nMaxInstances:指定管道能够创建实例的最大数目。
nOutBufferSize:指定输出缓冲区所保留的字节数。
nInBufferSize: 指定为输入缓冲区所保留的字节数。
nDefaultTimeOut:指定默认的超时值,单位是ms,同一个管
道的不同实例必须指定同样的超时值。
lpSecurityAttributes:指定命名管道的安全描述符,并确定
子进程是否可以继承这个函数返回的
管道句柄。
2、服务器端程序
private:
HANDLE hPipe;
hPipe=NULL;
/******************创建命名管道****************************/
hPipe=CreateNamePipe("\\\\.\\pipe\\MyPipe",
PIPE_ACCESS_DUPLEX|FILE_FLAG_OVERLAPPED,
//PIPE_ACCESS_DUPLEX双向模式
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);
/**************创建命名管道结束****************************/
/***************读取数据***********************************/
char buf[100];
DWORD dwRead;
if(!ReadFile(hPipe,buf,100,&dwRead,NULL))
{
MessageBox("读取数据失败!");
return;
}
MessageBox(buf);
/******************读取数据结束************************/
/*****************写入数据*****************************/
char buf[]="http://www.sunxin.org";
DWORD dwWrite;
if(!WriteFile(hPipe,buf,strlen(buf)+1,&dwWrite,NULL))
{
MessageBox("写入数据失败!");
return;
}
/****************写入数据结束**********************/
if(hPipe)
CloseHandle(hPipe);
3、客户端程序
private:
HANDLE hPipe;
hPipe=NULL;
/***************连接命名管道******************************/
//判断是否有可以利用的命名管道
if(!WaitNamedPipe("\\\\.\\pipe\\MyPipe",
NMPEAIT_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;
}
/****************连接命名管道结束*********************/
/******************读取数据*************************/
char buf[100];
DWORD dwRead;
if(!ReadFile(hPipe,buf,100,&dwRead,NULL))
{
MessageBox("读取数据失败!");
return;
}
MessageBox(buf);
/**************读取数据结束************************/
/************写入数据******************************/
char buf[]="命名管道测试程序";
DWORD dwWrite;
if(!WriteFile(hPipe,buf,strlen(buf)+1,&dwWrite,NULL))
{
MessageBox("写入数据失败!");
return;
}
/***************写入数据结束*********************/
if(hPipe)
CloseHandle(hPipe);
四、邮槽
1、基本知识
邮槽是基于广播通信体系设计出来的。它采用无连接的不可靠数据传输。
邮槽是一种单向的通信机制,创建邮槽的服务器进程
读取数据,打开邮槽的客户机进程写入数据。
HANDLE CreateMailslot(
LPCTSTR lpName,
DWORD nMaxMessageSize,
DWord lReadTimeout,
LPSECURITY_ATTRIBUTES lpSecurityAttributes);
参数:lpName: 指向一个空终止字符串的指针,该字符串指定了邮槽的名称,
该名称的格式必须是:"\\.\mailslot=[path]name"
其中前两个反斜杠之后字符标识服务器所在的机器名称,
圆点表示是本地主机,接着是硬编码的字符串:
"mailslot",这jgie字符不能改变,但大小写无所谓,
最后的字符串([path]name)就是程序员为邮槽取的名称。
nMaxMessageSize:由来指定可用被写入到邮槽的单一消息的最大尺寸,
网络可用发送任一大小的消息,可用设置为0。
lReadTimeout: 指定读取操作的超时时间间隔。以ms为单位。 如果0,
没有消息,函数立即返回。如果是
MAILSLOT_WAIT_FOREVER,在该函数将一直等待。
直到有消息可用。
lpSecurityAttributes:创建邮槽默认安全描述。
2、服务器端程序
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);
3、客户端程序
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);
第十节 进程间通信
原创
©著作权归作者所有:来自51CTO博客作者rosehacker2010的原创作品,请联系作者获取转载授权,否则将追究法律责任
提问和评论都可以,用心的回复会被更多人看到
评论
发布评论
相关文章
-
Linux进程间通信
进程间通信方式,命名管道,共享内存。
共享内存 管道文件 -
第十节 死信队列
一、基本功能 场景一:订单下单之后30分钟后,如果用户没有付钱,则系统自动取消订
java rabbitmq 网络 数据 服务器 -
第十节TypeScript string
根据主机的语言环境把字符串转换为小写,只有几种语言(如土耳其语)具有地方特有的大小写映射。据主机的语言环境把字符串转换为大写
typescript javascript 前端 字符串 字符串转换 -
Python 第十节 第十二课
[toc]os 模块-文件和目录操作 我们可以通过前面讲的文件对象实现对于文件内
多级目录 目录操作 方法名 -
第十节 Shiro集成SSM框架
一、搭建基本的SSM框架 首先告诉大家一个好消息,现在github的私有仓库免费咯。 好,开始本可以直接查看搭建后的代码并进入第三步中直接...
spring java 后端 自定义 html