管道是操作系统提供的进程之间的通讯方式之一,在所有的进程间通讯的方式中是最简单的。就像读文件、写文件的方式一样,二期也用的是读文件和写文件的函数进行进程间的通讯。
根据管道的方向分为:
- 单管道 只能单向进行传输
- 双管道 可以两进程之间互相传输
管道的命名方式可分为
- 命名管道 任意进程之间进行数据的传输
- 匿名管道 只能用于父进程和启动子进程之间通讯
使用函数:
- CreatePipe
CreatePipe是创建一个匿名管道,并从中得到读写管道的句柄。
BOOL WINAPI CreatePipe
( _Out_PHANDLE hReadPipe,
_Out_PHANDLE hWritePipe,
_In_opt_LPSECURITY_ATTRIBUTES lpPipeAttributes,
_In_DWORD nSize
);
-
hReadPipe[out]返回一个可用于读管道数据的文件句柄
-
hWritePipe[out]返回一个可用于写管道数据的文件句柄
-
lpPipeAttributes[in, optional]传入一个SECURITY_ATTRIBUTES结构的指针,该结构用于决定该函数返回的句柄是否可被子进程继承。如果传NULL,则返回的句柄是不可继承的。
该结构的lpSecurityDescriptor成员用于设定管道的安全属性,如果传NULL,那么该管道将获得一个默认的安全属性,该属性与创建该管道的用户账户权限ACLs的安全令牌(token)相同。
- nSize[in]管道的缓冲区大小。但是这仅仅只是一个理想值,系统根据这个值创建大小相近的缓冲区。如果传入0
,那么系统将使用一个默认的缓冲区大小。
注意:
匿名管道不允许异步操作,所以如在一个管道中写入数据,且缓冲区已满,那么除非另一个进程从管道中读出数据,从而腾出了缓冲区的空间,否则写入函数不会返回
- SECURITY_ATTRIBUTES
这个结构为很多函数创建对象时提供安全性设置。如:CreateFileCreatePipeCreateProcessRegCreateKeyEx,RegSaveKeyEx。
typedef struct _SECURITY_ATTRIBUTES {
DWORD nLength; //结构体的大小,可用SIZEOF取得
LPVOID lpSecurityDescriptor; //安全描述符包含和被保护对象相
// 关联的安全信息的数据结构。安全描述符包括谁拥有对象,
//以何种方式访问以及何种审查访问类型等信息。
BOOL bInheritHandle ;//安全描述的对象能否被新创建的进程继承
} SECURITY_ATTRIBUTES,* PSECURITY_ATTRIBUTES;
- CreateProcess
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
);
- lpApplicationName:指向一个NULL结尾的、用来指定可执行模块的字符串。
- lpCommandLine:指向一个以NULL结尾的字符串,该字符串指定要执行的命令行。
- lpProcessAttributes:指向一个SECURITY_ATTRIBUTES结构体,这个结构体决定是否返回的句柄可以被子进程继承。如果lpProcessAttributes参数为空(NULL),那么句柄不能被继承。
- pThreadAttributes:同lpProcessAttribute,不过这个参数决定的是线程是否被继承.通常置为NULL.
- bInheritHandles:指示新进程是否从调用进程处继承了句柄。
- dwCreationFlags:指定附加的、用来控制优先类和进程的创建的标志。以下的创建标志可以以除下面列出的方式外的任何方式组合后指定。
CREATE_DEFAULT_ERROR_MODE | 新的进程不继承调用进程的错误模式。CreateProcess函数赋予新进程当前的默认错误模式作为替代。应用程序可以调用SetErrorMode函数设置当前的默认错误模式。这个标志对于那些运行在没有硬件错误环境下的多线程外壳程序是十分有用的。对于CreateProcess函数,默认的行为是为新进程继承调用者的错误模式。设置这个标志以改变默认的处理方式。 |
---|---|
CREATE_NEW_CONSOLE | 新的进程将使用一个新的控制台,而不是继承父进程的控制台。这个标志不能与DETACHED_PROCESS标志一起使用。 |
CREATE_NEW_PROCESS_GROUP | 新进程将是一个进程树的根进程。进程树中的全部进程都是根进程的子进程。新进程树的用户标识符与这个进程的标识符是相同的,由lpProcessInformation参数返回。进程树经常使用GenerateConsoleCtrlEvent函数允许发送CTRL+C或CTRL+BREAK信号到一组控制台进程。 |
CREATE_SEPARATE_WOW_VDM | 如果被设置,新进程将会在一个私有的虚拟DOS机(VDM)中运行。另外,默认情况下所有的16位Windows应用程序都会在同一个共享的VDM中以线程的方式运行。单独运行一个16位程序的优点是一个应用程序的崩溃只会结束这一个VDM的运行;其他那些在不同VDM中运行的程序会继续正常的运行。同样的,在不同VDM中运行的16位Windows应用程序拥有不同的输入队列,这意味着如果一个程序暂时失去响应,在独立的VDM中的应用程序能够继续获得输入。 |
CREATE_SHARED_WOW_VDM | 如果WIN.INI中的Windows段的DefaultSeparateVDM选项被设置为真,这个标识使得CreateProcess函数越过这个选项并在共享的虚拟DOS机中运行新进程。 |
CREATE_SUSPENDED | 新进程的主线程会以暂停的状态被创建,直到调用ResumeThread函数被调用时才运行。 |
CREATE_UNICODE_ENVIRONMENT | 如果被设置,由lpEnvironment参数指定的环境块使用Unicode字符,如果为空,环境块使用ANSI字符。 |
DEBUG_PROCESS | 如果这个标志被设置,调用进程将被当做一个调试程序,并且新进程会被当做被调试的进程。系统把被调试程序发生的所有调试事件通知给调试器。如果你使用这个标志创建进程,只有调用进程(调用CreateProcess函数的进程)可以调用WaitForDebugEvent函数。 |
DEBUG_ONLY_THIS_PROCESS | 如果此标志没有被设置且调用进程正在被调试,新进程将成为调试调用进程的调试器的另一个调试对象。如果调用进程没有被调试,有关调试的行为就不会产生。 |
DETACHED_PROCESS | 对于控制台进程,新进程没有访问父进程控制台的权限。新进程可以通过AllocConsole函数自己创建一个新的控制台。这个标志不可以与CREATE_NEW_CONSOLE标志一起使用。 |
CREATE_NO_WINDOW | 系统不为新进程创建CUI窗口,使用该标志可以创建不含窗口的CUI程序。 |
dwCreationFlags还用来控制新进程的优先类,优先类用来决定此进程的线程调度的优先级。如果下面的优先级类标志都没有被指定,那么默认的优先类是NORMAL_PRIORITY_CLASS,除非被创建的进程是IDLE_PRIORITY_CLASS。在这种情况下子进程的默认优先类是IDLE_PRIORITY_CLASS。
优先级 | 含义 |
---|---|
HIGH_PRIORITY_CLASS | 指示这个进程将执行时间临界的任务,所以它必须被立即运行以保证正确。这个优先级的程序优先于正常优先级或空闲优先级的程序。一个例子是Windows任务列表,为了保证当用户调用时可以立刻响应,放弃了对系统负荷的考虑。确保在使用高优先级时应该足够谨慎,因为一个高优先级的CPU关联应用程序可以占用几乎全部的CPU可用时间。 |
IDLE_PRIORITY_CLASS | 指示这个进程的线程只有在系统空闲时才会运行并且可以被任何高优先级的任务打断。例如屏幕保护程序。空闲优先级会被子进程继承。 |
NORMAL_PRIORITY_CLASS | 指示这个进程没有特殊的任务调度要求。 |
REALTIME_PRIORITY_CLASS | 指示这个进程拥有可用的最高优先级。一个拥有实时优先级的进程的线程可以打断所有其他进程线程的执行,包括正在执行重要任务的系统进程。例如,一个执行时间稍长一点的实时进程可能导致磁盘缓存不足或鼠标反映迟钝。 |
- lpEnvironment:指向一个新进程的环境块。如果此参数为空,新进程使用调用进程的环境。
- lpCurrentDirectory:指向一个以NULL结尾的字符串,这个字符串用来指定子进程的工作路径。这个字符串必须是一个包含驱动器名的绝对路径。如果这个参数为空,新进程将使用与调用进程相同的驱动器和目录。这个选项是一个需要启动应用程序并指定它们的驱动器和工作目录的外壳程序的主要条件。
- lpStartupInfo:指向一个用于决定新进程的主窗体如何显示的STARTUPINFO结构体。
typedef struct _STARTUPINFO
{
DWORD cb; //包含STARTUPINFO结构中的字节数.如果Microsoft将来扩展该结构,
//它可用作版本控制手段.应用程序必须将cb初始化为sizeof(STARTUPINFO)
PSTR lpReserved; //保留。必须初始化为N U L L
PSTR lpDesktop; //用于标识启动应用程序所在的桌面的名字。如果该桌面存在,
//新进程便与指定的桌面相关联。如果桌面不存在,
//便创建一个带有默认属性的桌面,并使用为新进程指定的名字。
//如果lpDesktop是NULL(这是最常见的情况),那么该进程将与当前桌面相关联
PSTR lpTitle; //用于设定控制台窗口的名称。如果l p Ti t l e 是N U L L ,则可执行文件的名字将用作窗口名
DWORD dwX; //用于设定应用程序窗口在屏幕上应该放置的位置的x 和y 坐标(以像素为单位)。
DWORD dwY; // 只有当子进程用CW_USEDEFAULT作为CreateWindow的x参数来创建它的第一个重叠窗口时,
//才使用这两个坐标。若是创建控制台窗口的应用程序,这些成员用于指明控制台窗口的左上角
DWORD dwXSize; //用于设定应用程序窗口的宽度和长度(以像素为单位)只有dwYsize
// 当子进程将C W _ U S E D E FA U LT 用作C r e a t e Wi n d o w 的
//n Wi d t h参数来创建它的第一个重叠窗口时,才使用这些值。
//若是创建控制台窗口的应用程序,这些成员将用于指明控制台窗口的宽度
DWORD dwYSize;
DWORD dwXCountChars; //用于设定子应用程序的控制台窗口的宽度和高度(以字符为单位)
DWORD dwYCountChars;
DWORD dwFillAttribute; //用于设定子应用程序的控制台窗口使用的文本和背景颜色
DWORD dwFlags; //请参见下一段和表4 - 7 的说明
WORD wShowWindow; //用于设定如果子应用程序初次调用的ShowWindow将SW_SHOWDEFAULT作为
// nCmdShow 参数传递时,该应用程序的第一个重叠窗口应该如何出现。
// 本成员可以是通常用于ShowWindow 函数的任何一个S W _ *标识符
WORD cbReserved2; //保留。必须被初始化为0
PBYTE lpReserved2; //保留。必须被初始化为N U L L
HANDLE hStdInput; //用于设定供控制台输入和输出用的缓存的句柄。
//按照默认设置hStdInput用于标识键盘缓存,
HANDLE hStdOutput; //hStdOutput和hStdError用于标识控制台窗口的缓存
HANDLE hStdError;
} STARTUPINFO, *LPSTARTUPINFO;
表4 - 7
标志 | 标志 |
---|---|
STARTF_USESIZE | 使用d w X S i z e 和d w Y S i z e 成员 |
STARTF_USESHOWWINDOW | 使用w S h o w Wi n d o w 成员 |
STARTF_USEPOSITION | 使用d w X 和d w Y 成员 |
STARTF_USECOUNTCHARS | 使用d w X C o u n t C h a r s 和dwYCount Chars 成员 |
STARTF_USEFILLATTRIBUTE | /使用d w F i l l A t t r i b u t e 成员 |
STARTF_USESTDHANDLES | 使用h S t d I n p u t 、h S t d O u t p u t 和h S t d E r r o r 成员 |
STARTF_RUN_FULLSCREEN | 强制在x 8 6 计算机上运行的控制台应用程序以全屏幕方式启动运行 |
另外还有两个标志,即STARTF_FORCEONFEEDBACK 和STARTF_+FORCEOFFF -EEDBACK ,当启动一个新进程时,它们可以用来控制鼠标的光标。由于Windows支持真正的多任务抢占式运行方式,因此可以启动一个应用程序,然后在进程初始化时,使用另一个程序。为了向用户提供直观的反馈信息,C r e a t e P r o c e s s 能够临时将系统的箭头光标改为一个新光标,即沙漏箭头光标:
该光标表示可以等待出现某种情况,也可以继续使用系统。当启动另一个进程时,CreateProcess函数使你能够更好地控制光标。当设定STARTF_FORCEONFEEDBACK标志时,C r e a t e P r o c e s s 并不将光标改为沙漏。
STARTF_FORCEONFEEDBACK可使CreateProcess能够监控新进程的初始化,并可根据结果来改变光标。当使用该标志来调用CreateProcess时,光标改为沙漏。过2 s 后,如果新进程没有调用G U I ,CreateProcess 将光标恢复为箭头。
如果该进程在2 s 内调用了GUI ,CreateProcess将等待该应用程序显示一个窗口。这必须在进程调用G U I 后5 s 内发生。如果没有显示窗口,CreateProcess就会恢复原来的光标。如果显示了一个窗口,CreateProcess将使沙漏光标继续保留5 s 。如果某个时候该应用程序调用了G e t M e s s a g e 函数,指明它完成了初始化,那么C r e a t e P r o c e s s 就会立即恢复原来的光标,并且停止监控新进程。
- lpProcessInformation:指向一个用来接收新进程的识别信息的PROCESS_INFORMATION结构体。
typedef struct_PROCESS_INFORMATION{
HANDLE hProcess;
HANDLE hThread;
DWORD dwProcessId;
DWORD dwThreadId;
}PROCESS_INFORMATION;
① hProcess:返回新进程的句柄。
② hThread:返回主线程的句柄。
③ dwProcessId:返回一个全局进程标识符。该标识符用于标识一个进程。从进程被
创建到终止,该值始终有效。
④ dwThreadId:返回一个全局线程标识符。该标识符用于标识一个线程。从线程被创
建到终止,该值始终有效。
如果函数执行成功,返回非零值。如果函数执行失败,返回零,可以使用GetLastError函数获得错误的附加信息。
- ReadFile
从文件指针指向的位置开始将数据读出到一个文件中, 且支持同步和异步操作,如果文件打开方式没有指明FILE_FLAG_OVERLAPPED的话,当程序调用成功时,它将实际出文件的字节数保存到lpBuffer指明的地址空间中。FILE_FLAG_OVERLAPPED 允许对文件进行重叠操作如果文件要交互使用的话,当函数调用完毕时要记得调整文件指针。从文件中读出数据。
BOOL ReadFile(
HANDLE hFile, //文件的句柄
LPVOID lpBuffer, //用于保存读入数据的一个缓冲区
DWORD nNumberOfBytesToRead, //要读入的字节数
LPDWORD lpNumberOfBytesRead, //指向实际读取字节数的指针
LPOVERLAPPED lpOverlapped
//如文件打开时指定了FILE_FLAG_OVERLAPPED,那么必须,用这个参数引用一个特殊的结构。
//该结构定义了一次异步读取操作。否则,应将这个参数设为NULL
);
FILE_FLAG_OVERLAPPED 文件或设备被打开或创建异步I / O。 当后续的I /
O操作完成这个句柄,OVERLAPPED结构中指定的事件 将被设置为有信号状态。 如果这个标志被指定,该文件可用于同时读取和写入操作。
如果没有指定这个标志,然后被序列化I / O操作,即使调用读写函数指定一个OVERLAPPED结构。
- WriteFile
WriteFile是一个函数,可以将数据写入一个文件或者I/O设备。该函数比fwrite函数要灵活的多,也可将这个函数应用于对通信设备、管道、套接字以及邮槽的处理。
BOOL WriteFile(
HANDLE hFile,//文件句柄
LPCVOID lpBuffer,//数据缓存区指针
DWORD nNumberOfBytesToWrite,//你要写的字节数
LPDWORD lpNumberOfBytesWritten,//用于保存实际写入字节数的存储区域的指针
LPOVERLAPPED lpOverlapped//OVERLAPPED结构体指针
);
-
hFile Long 一个文件的句柄
-
lpBuffer Any,参数类型:指针,指向将写入文件的 数据缓冲区 nNumberOfBytesToWrite Long,要写入数据的字节数量。如写入零字节,表示什么都不写入,但会更新文件的“上一次修改时间”。针对位于远程系统的命名管道,限制在65535个字节以内
-
lpNumberOfBytesWritten Long,实际写入文件的字节数量(此变量是用来返回的 )
-
lpOverlapped OVERLAPPED,倘若在指定FILE_FLAG_OVERLAPPED的前提下打开文件,这个参数就必须引用一个特殊的结构。那个结构定义了一次异步写操作。否则,该参数应置为空(将声明变为ByVal As Long,并传递零值)
从文件指针指向的位置开始将数据写入到一个文件中, 且支持同步和异步操作,
如果文件打开方式没有指明FILE_FLAG_OVERLAPPED的话,当程序调用成功时,它将实际写入文件的字节数保存到lpNumberOfBytesWriten指明的地址空间中
如果文件要交互使用的话,当函数调用完毕时要记得调整文件指针
- PeekNamedPipe
预览一个管道中的数据,或取得与管道中的数据有关的信息。
BOOL WINAPI PeekNamedPipe(
__in HANDLE hNamedPipe, //管道句柄
__out_opt LPVOID lpBuffer, //读取输出缓冲区,可选
__in DWORD nBufferSize, //缓冲区大小
__out_opt LPDWORD lpBytesRead, //接收从管道中读取数据的变量的指针,可选
__out_opt LPDWORD lpTotalBytesAvail, //接收从管道读取的字节总数
__out_opt LPDWORD lpBytesLeftThisMessage
);
- hNamedPipe [in]管道句柄。这个参数可以是一个命名管道实例句柄,返回,由CreateNamedPipe或CreateFile函数,或者它可以是一个匿名管道的读端句柄,返回由CREATEPIPE功能。句柄必须有GENERIC_READ权限的管道。
- lpBuffer [out, optional]接收从管道读取数据的缓冲区的指针。如果没有数据要读取,此参数可以为NULL。
- nBufferSize [in]lpBuffer参数以字节为单位,由指定的缓冲区大小。如果lpBuffer是NULL,则忽略此参数。
- pBytesRead [out, optional]接收从管道中读取的字节数的变量的指针。此参数可以为NULL,如果没有数据要读取。
- lpTotalBytesAvail [out, optional]一个指针变量,接收从管道读取的字节总数。此参数可以为NULL,如果没有数据要读取。
- lpBytesLeftThisMessage [out, optional]指向剩余的字节数的变量的指针消息。此参数将是零字节类型的命名管道或匿名管道。此参数可以为NULL,如果没有数据要读取。
- 返回值
如果函数成功,返回值为非零。
如果函数失败,返回值是零。为了获得更多错误信息,调用GetLastError。
例程:
单管道 :应用程序通过创建子进程执行应用程序输入的命令,之后将子进程通过命令得到的结果传输到管道,然后应用程序通过管道获取子进程返回的信息。
void C单管道Dlg::OnBnClickedRun()
{
// TODO: 在此添加控件通知处理程序代码
HANDLE hPWrite,hPRead;//定义管道的写、读句柄
SECURITY_ATTRIBUTES sa = {0};//结构包含一个对象的安全描述符,
//并指定检索到指定这个结构的句柄是否是可继承的。
sa.nLength = sizeof(sa);//设置结构体的大小
sa.bInheritHandle = TRUE;//设置安全提示符
BOOL bCreate;
bCreate = CreatePipe(&hPRead, &hPWrite, &sa, 0);//穿件管道,返回为BOOL型
if (!bCreate)
{
MessageBox(_T("创建管道失败"));
return;
}
PROCESS_INFORMATION pi = {0};//创建进程时相关的数据结构之一,
//该结构返回有关新进程及其主线程的信息
STARTUPINFO si = {0};//指定新进程的主窗口特性的一个结构。
si.cb = sizeof(si);//设置结构体的大小
si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);//设定控制台输入和输出的缓存句柄,
//默认为标识键盘数据
si.hStdOutput = si.hStdError = hPWrite; //用于标识控制台窗口的缓存
//将管道的一段绑定到进程上面,
//hPWrite为管道的写句柄
//si.wShowWindow = TRUE;
si.wShowWindow = SW_HIDE; //设置进程窗口不需要显示
si.dwFlags = STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES; //标志进程使用那些成员
//TCHAR szCmd[MAX_PATH * 2] = _T("cmd");
TCHAR szCmd[MAX_PATH*2] = {0};
GetDlgItemText(IDC_EDIT_INPUT,szCmd,MAX_PATH*2);
//bCreate = CreateProcess(NULL,szCmd,NULL,NULL,TRUE,CREATE_NEW_CONSOLE,NULL,NULL,&si,&pi);
bCreate = CreateProcess(NULL, szCmd, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi);//创建进程
CloseHandle(pi.hThread);//关闭进程中的线程
CloseHandle(pi.hProcess);//关闭线程
if (!bCreate)
{
CloseHandle(hPWrite);//创建失败,关闭管道写进程
CloseHandle(hPRead);//创建失败,关闭管道读进程
MessageBox(_T("创建进程失败"));
}
else
{
CString str;
CloseHandle(hPWrite);//创建成功,关闭管道写进程
TCHAR szBuff[4096];
DWORD dwRead;
while (1)
{
memset(szBuff,0,sizeof(szBuff));
if (!ReadFile(hPRead,szBuff,4096,&dwRead,NULL))//读取管道中的信息
{
break;
}
str += szBuff;
SetDlgItemText(IDC_EDIT_OUTPUT,str);
}
CloseHandle(hPRead);
}
}
双管道:应用程序在启动窗口的构造函数中创建输入输出管道和子进程,在点击执行命令之后,应用程序通过输出管道将命令写入到输出管道中,子进程通过输出管道获取执行命令,执行之后,子进程将输出的结果通过输入进程写入到输入进程中,应用程序再通过输入管道获取子进程的返回结果。
1、定义全局变量
HANDLE m_outWrite, m_inRead; //创建输出写句柄和输入读句柄的成员变量
2、定义全局命令数组
TCHAR szCmd[MAX_PATH * 2] = _T("cmd");//定义一个全局命令变量
3、创建管道和进程
C双管道Dlg::C双管道Dlg(CWnd* pParent /*=NULL*/)
: CDialogEx(C双管道Dlg::IDD, pParent)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
HANDLE hOutRead, hInWrite;//定义输出管道的写句柄句柄和输入管道的写句柄
SECURITY_ATTRIBUTES sa = { 0 };//结构包含一个对象的安全描述符,
//并指定检索到指定这个结构的句柄是否是可继承的。
sa.nLength = sizeof(sa);//设置结构体的大小
sa.bInheritHandle = TRUE;//设置安全提示符
BOOL bCreate;
bCreate = CreatePipe(&m_inRead, &hInWrite, &sa, 0);//创建输入管道,返回为BOOL型
if (!bCreate)
{
MessageBox(_T("创建管道失败"));
return;
}
bCreate = CreatePipe(&hOutRead, &m_outWrite, &sa, 0);//创建输出管道,返回为BOOL型
if (!bCreate)
{
MessageBox(_T("创建管道失败"));
return;
}
PROCESS_INFORMATION pi = { 0 };//创建进程时相关的数据结构之一,
//该结构返回有关新进程及其主线程的信息
STARTUPINFO si = { 0 };//指定新进程的主窗口特性的一个结构。
si.cb = sizeof(si);//设置结构体的大小
si.hStdInput = hOutRead;//设定控制台输入和输出的缓存句柄,
//默认为标识键盘数据
si.hStdOutput = si.hStdError = hInWrite; //用于标识控制台窗口的缓存
//将管道的一段绑定到进程上面,
//hPWrite为管道的写句柄
//si.wShowWindow = TRUE;
si.wShowWindow = SW_HIDE; //设置进程窗口不需要显示
si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES; //标志进程使用那些成员
bCreate = CreateProcess(NULL, szCmd, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi);//创建进程
CloseHandle(pi.hThread);//关闭进程中的线程
CloseHandle(pi.hProcess);//关闭线程
if (!bCreate)
{
MessageBox(_T("创建进程失败"));
}
CloseHandle(hOutRead);
CloseHandle(hInWrite);
}
4、执行命令
void C双管道Dlg::OnBnClickedRun()
{
// TODO: 在此添加控件通知处理程序代码
GetDlgItemText(IDC_EDIT_INPUT,szCmd,MAX_PATH*2);//获取输入框输入的命令,将其存放到szCmd数组中
strcat(szCmd,"\n");//按下一个回车
DWORD dwBytes;
WriteFile(m_outWrite,szCmd,strlen(szCmd),&dwBytes,NULL);//将输入的命令写入到输出管道中
Sleep(500);
CString str;
TCHAR szBuff[4096] = {0};
DWORD dwRead;
while (PeekNamedPipe(m_inRead,szBuff,4096,&dwRead,NULL,0) && dwRead > 0)//判断输入管道中有没有数值
{
ReadFile(m_inRead, szBuff, dwRead, &dwRead, NULL);//读取管道中的信息
str += szBuff;
SetDlgItemText(IDC_EDIT_OUTPUT, str);
}
}
5、释放成员变量句柄
C双管道Dlg::~C双管道Dlg()
{
CloseHandle(m_inRead);
CloseHandle(m_outWrite);
}