我的程序调用 cl.exe 并使用管道进行通信。当我试图理解它时,我试图在 Windows 上使用管道搜索 IPC,但找不到太多资源。我发现下面的链接与我的代码有 90% 的相似度,但对每个步骤的描述非常少。
http://support.microsoft.com/en-us/kb/190351
有人可以向我解释一下这个程序中的父子关系是如何工作的吗?为什么使用重复句柄?
代码片段:
{
HANDLE hOutputReadTmp,hOutputRead,hOutputWrite;
HANDLE hInputWriteTmp,hInputRead,hInputWrite;
HANDLE hErrorWrite;
SECURITY_ATTRIBUTES sa;
// Set up the security attributes struct.
sa.nLength= sizeof(SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = TRUE;
// Create the child output pipe.
if (!CreatePipe(&hOutputReadTmp,&hOutputWrite,&sa,0))
{
error("Creation of child process output pipe failed");
return false;
}
// Create a duplicate of the output write handle for the std error
// write handle. This is necessary in case the child application
// closes one of its std output handles.
if (!DuplicateHandle(GetCurrentProcess(),hOutputWrite,
GetCurrentProcess(),&hErrorWrite,0,
TRUE,DUPLICATE_SAME_ACCESS))
{
error("Duplication of child process output pipe failed");
return false;
}
// Create the child input pipe.
if (!CreatePipe(&hInputRead,&hInputWriteTmp,&sa,0))
{
error("Creation of child process input pipe failed");
return false;
}
// Create new output read handle and the input write handles. Set
// the Properties to FALSE. Otherwise, the child inherits the
// properties and, as a result, non-closeable handles to the pipes
// are created.
if (!DuplicateHandle(GetCurrentProcess(),hOutputReadTmp,
GetCurrentProcess(),
&hOutputRead, // Address of new handle.
0,FALSE, // Make it uninheritable.
DUPLICATE_SAME_ACCESS))
{
error("Creation of child process read handle failed");
return false;
}
if (!DuplicateHandle(GetCurrentProcess(),hInputWriteTmp,
GetCurrentProcess(),
&hInputWrite, // Address of new handle.
0,FALSE, // Make it uninheritable.
DUPLICATE_SAME_ACCESS))
{
error("Creation of child process write handle failed");
return false;
}
// Close inheritable copies of the handles you do not want to be
// inherited.
CloseHandle(hOutputReadTmp);
CloseHandle(hInputWriteTmp);
// Get std input handle so you can close it and force the ReadFile to
// fail when you want the input thread to exit.
HANDLE hStdIn = NULL;
if ( (hStdIn = GetStdHandle(STD_INPUT_HANDLE)) == INVALID_HANDLE_VALUE )
TRACE("GetStdHandle");
STARTUPINFO Si;
Si.lpDesktop = NULL;
Si.cb = sizeof(Si);
Si.lpReserved = NULL;
Si.lpTitle = NULL;
Si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW | STARTF_USECOUNTCHARS;
Si.dwXCountChars = 10;
Si.dwYCountChars = 8;
Si.wShowWindow = SW_HIDE;
Si.cbReserved2 = 0;
Si.lpReserved2 = NULL;
Si.hStdOutput = hOutputWrite;
Si.hStdInput = hInputRead;
Si.hStdError = hErrorWrite;
PROCESS_INFORMATION Pi;
// Create and start the child process
BOOL processCreated = CreateProcess( NULL,
const_cast<char*>(m_command.c_str()),
NULL,
NULL,
TRUE,
GetCreationFlags(),
NULL,
m_workingDir.c_str(),
&Si,
&Pi);
if (!processCreated)
{
error("Creation of child process failed");
return false;
}
// Close pipe handles (do not continue to modify the parent).
// You need to make sure that no handles to the write end of the
// output pipe are maintained in this process or else the pipe will
// not close when the child process exits and the ReadFile will hang.
CloseHandle(hOutputWrite);
CloseHandle(hInputRead);
CloseHandle(hErrorWrite);
// Read the child's output.
if (!ReadAndHandleOutput(hOutputRead))
{
// Something went wrong so kill and exit
CloseHandle(hOutputRead);
CloseHandle(hInputWrite);
error("Read of compile process result failed");
TerminateProcess(Pi.hProcess, -1);
CloseHandle(Pi.hProcess);
CloseHandle(Pi.hThread);
return false;
}
CloseHandle(hOutputRead);
CloseHandle(hInputWrite);
// Wait for the child process to die
WaitForSingleObject(Pi.hProcess, INFINITE);
if (!GetExitCodeProcess(Pi.hProcess, &m_exitCode))
{
error("Read of child process exit code failed");
CloseHandle(Pi.hProcess);
CloseHandle(Pi.hThread);
return false;
}
CloseHandle(Pi.hProcess);
CloseHandle(Pi.hThread);
}
最佳答案
CreatePipe - 使用 ZwCreateNamedPipe[CreateNamedPipe]
和 ZwOpenFile [CreateFile(OPEN_EXISTING)]
创建命名管道对。
pair 的一个实例将存在于我们的进程中(没有继承标志),第二个实例将被复制到子进程(必须具有继承标志)。然而我们只有一个通用参数 LPSECURITY_ATTRIBUTES
,我们可以在其中设置继承标志。因此,如果设置了此标志 - 两个实例都将具有继承的属性。这里可以有几种解决方案。我们不能使用CreatePipe
,而是直接调用ZwCreateNamedPipe
和ZwOpenFile
来正确继承设置。或者我们可以使用 SetHandleInformation
更改继承设置。但是示例的作者选择了最差的(根据逻辑和效率)——使用 DuplicateHandle
为管道实例创建另一个句柄——已经没有继承标志。然后关闭原始 handle 。但是可以使用 DUPLICATE_CLOSE_SOURCE
标志来避免下一次 CloseHandle
调用 - 令人震惊的无知。在调用 CreateProcess
之后 - 继承的句柄被复制到子进程,我们可以在原始进程中关闭它。所以此时我们有 2 个管道 channel 并开始读/写..
关于c++ - IPC 在 Windows 上使用管道,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29292924/