注意:匿名管道只能在父进程和子进程之间进行,所以必须由父进程通过CreateProcess来创建子进程才能形成父子关系.否则,不能形成父子进程关系.
CreatePipe 创建一个匿名管道,返回管道的读句柄,写句柄.
BOOL CreatePipe(
PHANDLE hReadPipe,
PHANDLE hWritePipe,
LPSECURITY_ATTRIBUTES lpPipeAttributes,
DWORD nSize
);
前两个参数为管道的读句柄和写句柄
第三个参数是指向SECURITY_ATTRIBUTES指针,检测返回的句柄是否可以为子进程所继承,如果这个参数是NULL,这个句柄不能够被继承.在其他大多函数中,涉及到SECURITY_ATTRIBUTES一般都默认设置成NULL,让系统设置默认的安全描述符,得到的句柄不能够被子进程所继承.但这里不能设置成NULL,因为对于匿名管道这能在父子进程之间进行通信,对于子进程如果想得到匿名管道句柄,只能从父管道继承而来,当一个子进程从父进程继承管道的读写句柄,就能和父进程通信了.
最后一个参数设置管道的缓冲区大小,0为缺省,系统提供默认值.
这里
typedef struct _SECURITY_ATTRIBUTES {
DWORD nLength;
LPVOID lpSecurityDescriptor;
BOOL bInheritHandle;
} SECURITY_ATTRIBUTES,
*PSECURITY_ATTRIBUTES;
第一个参数为结构提的长度,为sizeof(SECURITY_ATTRIBUTES).
第二个成员是安全描述符,这里设置成NULL,让系统自动设置,但不能整个结构设置为NULL,那样第三个变量也会设置成NULL,
第三个成员为真,则可以被子进程所继承.
Createprocess创建一个进程
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
);
上面函数可以用第一个参数传递一个可执行模块的名字,如果用它来加载可执行的模块名,而没有相对路径,程序会在当前文件目录下查找,而不会到系统路径下查找要执行的模块.如果找不到就以失败返回.同时,它不会给可执行模块自动添加扩展名.
第二个参数来传递可执行模块的参数.
也可以用它来添加可执行模块,它在当前目录查找不到会到系统路径去查找,同时如果没有写可执行模块的扩展名,它会自动扩展可执行文件的扩展名.通常同时用它来传递可执行模块名,和参数.
代码片段:
创建管道
定义类成员变量:
HANDLE hWrite;
HANDLE hRead;
构造函数初始化这两个句柄
CParentView::CParentView()
{
// TODO: add construction code here
hRead=NULL;
hWrite=NULL;
}
析构函数
CParentView::~CParentView()
{
if(hRead)
CloseHandle(hRead);
if(hWrite)
CloseHandle(hWrite);
}
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;//进程信息结构体指针
/*
将结构提中的所有成员都设置成0
*/
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,hWrite设置成NULL,防止析构函数再次把这两个句柄关闭
hRead=NULL;
hWrite=NULL;
MessageBox("创建子进程失败!");
return;
}
else
{
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
}
从匿名管道读取数据,和写入数据
用ReadFile 和 WriteFile 来向管道中写入数据和读取数据
void CParentView::OnPipeRead()
{
// TODO: 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()
{
// TODO: 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;
}
}
子进程读取数据和写入数据
同样创建成员变量
HANDLE hWrite;
HANDLE hRead;
CParentView::CParentView()
{
hRead=NULL;
hWrite=NULL;
}
CParentView::~CParentView()
{
if(hRead)
CloseHandle(hRead);
if(hWrite)
CloseHandle(hWrite);
}
OnInitialUpdate()是窗口创建完成之后第一个调用的函数
void CChildView::OnInitialUpdate()
{
CView::OnInitialUpdate();
//到子进程的标准输入和标准输出句柄
hRead=GetStdHandle(STD_INPUT_HANDLE);
hWrite=GetStdHandle(STD_OUTPUT_HANDLE);
}
void CChildView::OnPipeRead()
{
char buf[100];
DWORD dwRead;
if(!ReadFile(hRead,buf,100,&dwRead,NULL))
{
MessageBox("读取数据失败!");
return;
}
MessageBox(buf);
}
void CChildView::OnPipeWrite()
{
char buf[]="匿名管道测试程序";
DWORD dwWrite;
if(!WriteFile(hWrite,buf,strlen(buf)+1,&dwWrite,NULL))
{
MessageBox("写入数据失败!");
return;
}
}