Create a Process and Read Its Output

This is a snippet of windows C++ code to create a process and read its output until some specific string is printed. This is useful for programmer to start a server and only to return until the server is started, as sometimes server may take some seconds to initialize.

BOOL CreateProcessAndWait(char* cmdline, int flag,
STARTUPINFO *si, PROCESS_INFORMATION *pi,
const char* keyString)
{
HANDLE hOutputReadTmp,hOutputRead,hOutputWrite;
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)) {
printf("CreatePipe\n");
}
// closes one of its std output handles.
if (!DuplicateHandle(GetCurrentProcess(),hOutputWrite,
GetCurrentProcess(),&hErrorWrite,0,
TRUE,DUPLICATE_SAME_ACCESS))
printf("DuplicateHandle");
// 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))
printf("DupliateHandle");

ZeroMemory(si, sizeof(STARTUPINFO));
si->cb = sizeof(STARTUPINFO);
ZeroMemory(pi, sizeof(PROCESS_INFORMATION));
flag = CREATE_NEW_PROCESS_GROUP | flag;
si->dwYCountChars = 5000;
si->dwFlags |= STARTF_USECOUNTCHARS;
si->dwFlags |= STARTF_USESTDHANDLES;
si->hStdOutput = hOutputWrite;
si->hStdError = hErrorWrite;

int ret = CreateProcess(NULL,
cmdline, /* command line */
NULL, /* Security */
NULL, /* thread */
TRUE, /* inherit handles */
flag, /* start flags */
NULL, /* winenv, */
NULL, /* current directory */
si, pi);
if (ret != -1)
{
CHAR lpBuffer[256];
DWORD nBytesRead;
DWORD keyLength = strlen(keyString);
DWORD index = 0;
memset(lpBuffer, 0, sizeof(lpBuffer));

DWORD dwTimeoutThreadId;
HANDLE hTimeoutThread = CreateThread(
NULL, // no security attribute
0, // stack size, BUGBUG:Try to use the limit size!
(LPTHREAD_START_ROUTINE) TimeoutThread,
(LPVOID) pi->hProcess, // thread parameter
0, // not suspended
&dwTimeoutThreadId); // returns thread ID

if (hTimeoutThread == NULL)
{
printf("No time out thread for specific string %s.\n",
keyString);
}
else CloseHandle(hTimeoutThread);

while(TRUE)
{
if (ReadFile(hOutputRead,lpBuffer + index,
sizeof(lpBuffer) - index,
&nBytesRead,NULL) && nBytesRead)
{
if ((index + nBytesRead >= keyLength)
&& strstr(lpBuffer, keyString))
{
break;
}
if (index + nBytesRead > sizeof(lpBuffer)
- keyLength) {
// move
for (DWORD i = 0; i < keyLength; i++) {
lpBuffer[i] = lpBuffer[index + nBytesRead
- keyLength + i];
}
index = keyLength;
memset(lpBuffer + keyLength, 0,
sizeof(lpBuffer) - keyLength);
} else {
index += nBytesRead;
}
}
}
}
return ret;
}

This entry was posted in C++, Snippet, Tricks. Bookmark the permalink.

Comments are closed.