i'm working on a project where i need to launch an external program (process) and send messages to its STDIN and read its STDOUT and STDERR.
I can't use anonymous pipes because i'm in a multi-threaded asynchronous environment, I read a lot of MSDN documentation and examples and i have something that somewhat works.
I created a named pipe and created multiple handles with the same name, each one for the different streams, the wait for incoming messages from STDOUT and STDERR (of the child process) is done in another thread.
I wanted to implement the send message part where i can write into the child's STDIN but i couldn't get it to work, or so i thought. I wrote a little program so i can see what's going on and used it as my child process.
the program gives you three choices 1 write to STDOUT 2 write to STDERR and 3 exit.
I have to questions/issues :
1- when i use std::cin to read what's coming from my parent/server program i can't get the value i'm sending, but when using fread to read a byte from STDIN it works and i can get my value.
2- i created the pipes with the FILE_FLAG_OVERLAPPED do i have to use the overlapped structure for my write operation (i couldn't get it to work), because i just used the Write function and put NULL on the overlapped structure.
STARTUPINFO si;
PROCESS_INFORMATION pi;
SECURITY_ATTRIBUTES sa;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
if (fHideConsole)
{
si.dwFlags |= STARTF_USESHOWWINDOW;
si.wShowWindow = SW_HIDE;
}
ZeroMemory(&pi, sizeof(pi));
// Sets the bInheritHandle flag so that pipes are inherited (TODO depends on what is open)
SECURITY_DESCRIPTOR saDesc;
InitializeSecurityDescriptor(&saDesc, SECURITY_DESCRIPTOR_REVISION);
SetSecurityDescriptorDacl(&saDesc, TRUE, NULL, FALSE);
sa.nLength = sizeof(sa);
sa.bInheritHandle = TRUE;
sa.lpSecurityDescriptor = &saDesc;
si.dwFlags |= STARTF_USESTDHANDLES;
si.hStdOutput = INVALID_HANDLE_VALUE;
si.hStdError = INVALID_HANDLE_VALUE;
si.hStdInput = INVALID_HANDLE_VALUE;
if (inReadCallback)
{
//if (!CreateOverlappedPipe(&fOutPipe, &outPipeWrite, &sa))
// err = GetLastError();
//if (!SetHandleInformation(fOutPipe, HANDLE_FLAG_INHERIT, 0))
// err = GetLastError();
fOutPipe = CreateNamedPipe(
L"\\\\.\\Pipe\\RemoteExeOut",
PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
PIPE_TYPE_BYTE | PIPE_WAIT,
PIPE_UNLIMITED_INSTANCES, // Number of pipes
kSizeRead, // Out buffer size
kSizeRead, // In buffer size
0, // Timeout in ms
&sa);
si.hStdOutput = CreateFileW(
L"\\\\.\\Pipe\\RemoteExeOut",
FILE_WRITE_DATA,
0, // No sharing
&sa,
OPEN_EXISTING,
0,
NULL);
}
if (inReadErrorCallback)
{
fErrPipe = CreateNamedPipe(
L"\\\\.\\Pipe\\RemoteExeErr",
PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
PIPE_TYPE_BYTE | PIPE_WAIT,
PIPE_UNLIMITED_INSTANCES, // Number of pipes
kSizeRead, // Out buffer size
kSizeRead, // In buffer size
0, // Timeout in ms
&sa);
si.hStdError = CreateFileW(
L"\\\\.\\Pipe\\RemoteExeErr",
FILE_WRITE_DATA,
0, // No sharing
&sa,
OPEN_EXISTING,
0,
NULL);
}
fInPipe = CreateNamedPipe(
L"\\\\.\\Pipe\\RemoteExeIn",
PIPE_ACCESS_OUTBOUND, //PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
PIPE_TYPE_BYTE | PIPE_WAIT,
PIPE_UNLIMITED_INSTANCES, // Number of pipes
kSizeRead, // Out buffer size
kSizeRead, // In buffer size
0, // Timeout in ms
&sa
);
si.hStdInput = CreateFileW(
L"\\\\.\\Pipe\\RemoteExeIn",
FILE_READ_DATA,
0, // No sharing
&sa,
OPEN_EXISTING,
0,
NULL);
if (CreateProcessW(nullptr, cmd, nullptr, nullptr, TRUE, 0, inEnvironment, currDir, &si, &pi))
{
// custom code to send to thread
fIsRunning = true;
fPid = pi.dwProcessId;
WaitData* wData = new WaitData{ pi.dwProcessId, static_cast<DWORD>(inTimeoutSeconds), this, inTerminatedCallback };
wData->readHandle = fOutPipe;
wData->readCallback = inReadCallback;
wData->errorHandle = fErrPipe;
wData->errorCallback = inReadErrorCallback;
fWaitingTask = new VTask(NULL, 0, eTaskStylePreemptive, WaitFct);
fWaitingTask->SetKind('WLEP');
fWaitingTask->SetKindData(reinterpret_cast<sLONG_PTR>(wData));
fWaitingTask->Run();
}
else
{
vThrowWin32Error(GetLastError()); // custom error handling
}
delete[] cmd;
delete[] currDir;
// Close process and thread handles.
if (pi.hProcess != INVALID_HANDLE_VALUE)
CloseHandle(pi.hProcess);
if (pi.hThread != INVALID_HANDLE_VALUE)
CloseHandle(pi.hThread);
if (si.hStdInput != INVALID_HANDLE_VALUE)
CloseHandle(si.hStdInput);
if (si.hStdOutput != INVALID_HANDLE_VALUE)
CloseHandle(si.hStdOutput);
if (si.hStdError != INVALID_HANDLE_VALUE)
CloseHandle(si.hStdError);
my write function :
DWORD dwWritten = 0;
OVERLAPPED ovr;
BOOL success = WriteFile(fInPipe, inBuffer, inSize, &dwWritten, nullptr);
if (!success)
{
DWORD err = GetLastError();
if (err == ERROR_BROKEN_PIPE)
DebugMsg(" !!!!!!!!! BROKEN PIPE !!!!!!!");
if (err == ERROR_IO_PENDING)
DebugMsg(" IO IS PENDING ASYNC USE");
}
Thanks in Advance.