Advertisement

02.07.2008 at 02:47PM PST, ID: 23146285
[x]
Attachment Details
[x]
The Solution Rating System

With so many solutions, how can you tell which solutions are most likely to help you and which ones are not? To provide you with a tool to use, we rate our solutions based on various elements that most accurately determine if a solution is a quality solution. To explain what factors affect the solution rating, here are the elements we take into consideration when formulating our solution rating.

  • The Grade of the Solution
  • The Zone Rank of the Expert Providing the Solution
  • The Number of Author and Expert Comments
  • The Number of Experts Contributing
  • The Feedback of the Community

Your Input Matters
Because of the way the system is set up, the most important variable in this equation is you. As a member of Experts Exchange, you are able to cast your vote on the quality of the solutions in regard to how complete, accurate, helpful and easy to understand each solution is. When you provide your feedback, each rating is adjusted accordingly. So, if you see a solution that has a poor rating that you think is a good solution, let us know by rating it. As you do, the rating will be adjusted and will become more accurate for other members of our site.

If you have any suggestions that you would like to make for our rating system, please ask a question in the Suggestions Zone of Community Support.

Thank you!

CreateProcess - not capturing stdout

Tags: C++
I am using some code i found to capture the stdout when using CreateProcess.  I am not getting anything, and not sure if my process is even running although i get no errors.  One thing i am thinking of is, when using the lpCurrentDirectory parameter, does this need a trailing \ or should the backslash be removed?  Currently it is removed.
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
154:
155:
156:
157:
158:
159:
160:
161:
162:
163:
164:
165:
166:
167:
168:
169:
170:
171:
172:
173:
174:
175:
176:
177:
178:
179:
180:
181:
182:
183:
184:
185:
186:
187:
188:
189:
190:
191:
192:
193:
194:
195:
196:
197:
198:
199:
200:
201:
202:
203:
204:
205:
206:
207:
208:
209:
210:
211:
212:
213:
214:
215:
216:
217:
218:
219:
220:
221:
222:
223:
224:
225:
226:
227:
228:
229:
230:
231:
232:
233:
234:
235:
236:
237:
238:
239:
240:
241:
242:
243:
244:
245:
246:
247:
248:
249:
250:
251:
252:
253:
254:
255:
256:
257:
258:
259:
260:
261:
262:
263:
264:
265:
266:
267:
268:
269:
270:
271:
272:
273:
274:
275:
276:
277:
278:
279:
280:
281:
282:
283:
284:
285:
286:
287:
288:
289:
290:
291:
292:
293:
294:
295:
296:
297:
298:
299:
300:
301:
302:
303:
304:
305:
306:
307:
308:
309:
310:
311:
312:
313:
314:
315:
316:
317:
318:
319:
320:
321:
322:
323:
324:
325:
326:
327:
328:
329:
330:
331:
332:
333:
334:
335:
336:
337:
338:
339:
340:
341:
342:
343:
344:
345:
346:
347:
348:
349:
350:
351:
352:
353:
354:
355:
356:
357:
358:
359:
360:
361:
362:
363:
364:
365:
366:
367:
368:
369:
370:
371:
372:
373:
374:
375:
376:
377:
378:
379:
380:
381:
382:
383:
384:
385:
386:
387:
388:
389:
390:
391:
392:
393:
394:
395:
396:
397:
398:
399:
400:
401:
402:
403:
404:
405:
406:
407:
408:
409:
410:
411:
412:
413:
414:
415:
416:
417:
418:
419:
420:
421:
422:
423:
424:
425:
426:
427:
428:
429:
430:
431:
432:
433:
434:
435:
436:
437:
438:
439:
440:
441:
442:
443:
444:
445:
446:
447:
448:
449:
450:
451:
452:
453:
454:
455:
456:
457:
458:
459:
460:
// .h file
#pragma once
#include <string.h>
#include <iostream>
#include <sstream>
#include <stdlib.h>
//#include <windows.h>
#include <afxwin.h>
#include <string.h>
#include <tchar.h>
 
class Shell
{
public:
	Shell();
	//int Execute(char* cmd, char* outbuf, char* startDir = NULL);
	int Execute(char* cmd, std::string* outstr, char* startDir = NULL);
	HANDLE ExecuteAsync(char* cmd, std::string* outstr, char* startDir = NULL);
 
   HANDLE hChildProcess;
   HANDLE hStdIn; // Handle to parents std input.
   HANDLE hPipeWrite; // Handle to parents std input.
   BOOL bRunThread;
 
   std::string str;
	//DWORD WINAPI GetAndSendInputThread(LPVOID lpvThreadParam);
	void ReadAndHandleOutput(HANDLE hPipeRead);
	HANDLE PrepAndLaunchRedirectedChild(char* cmd, HANDLE hChildStdOut,
                                     HANDLE hChildStdIn,
                                     HANDLE hChildStdErr, char* startDir);
 
	void ErrorExit(LPTSTR lpszFunction);
	void DebugError(char *pszAPI);
 
	char* _cmd;
	std::string* _outstr;
};
 
struct EXECARGS
{
	Shell* Shell;
	char* Cmd;
	char* StartDir;
	std::string* OutStr;
};
 
 
//C++ file
#define WINVER 0x0400
#include "Shell.h"
#include <process.h>
   /*++
 
      Copyright (c) 1998  Microsoft Corporation
 
      Module Name:
 
         Redirect.c
 
      Description:
          This sample illustrates how to spawn a child console based
          application with redirected standard handles.
 
          The following import libraries are required:
          user32.lib
 
      Dave McPherson (davemm)   11-March-98
 
   --*/ 
 
DWORD WINAPI GetAndSendInputThread(LPVOID lpvThreadParam);
 
Shell::Shell()
{
   hChildProcess = NULL;
   hStdIn = NULL; // Handle to parents std input.
   bRunThread = TRUE;
   hPipeWrite = NULL;
}
 
unsigned int __stdcall ExecuteOnThread(void* lpvThreadParam)
{
	EXECARGS* args = (EXECARGS*)lpvThreadParam;
	int ret = args->Shell->Execute(args->Cmd,args->OutStr,args->StartDir);
	delete args;
	return ret;
}
 
HANDLE Shell::ExecuteAsync(char* cmd, std::string* outstr, char* startDir)
{
	EXECARGS* args = new EXECARGS;
	args->Shell = this;
	args->Cmd = cmd;
	args->OutStr = outstr;
	args->StartDir = startDir;
 
	unsigned int dwThreadId;
	HANDLE hThread = (HANDLE)_beginthreadex(
		NULL,       // pointer to security attributes
		0,          // initial thread stack size
		ExecuteOnThread, // pointer to thread function
		args,          // argument for new thread
		0,          // creation flags (immediate)
		&dwThreadId // pointer to receive thread ID
	);
	return hThread;
}
 
//outbuf will be assigned new memory, so we must send in an uninitialized pointer
int Shell::Execute(char* cmd, std::string* outstr, char* startDir)
{
	HANDLE hProc;
	DWORD ret;
 
	#ifdef _DEBUG
	printf("Shell: cmd=%s\nShell: startDir=%s\n",cmd,startDir);
	#endif
	//if we aren't looking for the console output
	if( outstr == NULL)
	{
	printf("Executing with no console capture\n");
		hProc = PrepAndLaunchRedirectedChild(cmd,NULL,NULL,NULL,startDir);
		ret = STILL_ACTIVE;
		do
		{
			Sleep(200);
			GetExitCodeProcess(hProc,&ret);
		}
		while(ret == STILL_ACTIVE);
		return ret;
	}
 
    HANDLE hOutputReadTmp,hOutputRead,hOutputWrite;
    HANDLE hInputWriteTmp,hInputRead,hInputWrite;
    HANDLE hErrorWrite;
    HANDLE hThread;
    DWORD ThreadId;
    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))
        DebugError("CreatePipe");
 
 
    // 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))
        DebugError("DuplicateHandle");
 
 
    // Create the child input pipe.
    if (!CreatePipe(&hInputRead,&hInputWriteTmp,&sa,0))
        DebugError("CreatePipe");
 
 
    // 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))
        DebugError("DupliateHandle");
 
    if (!DuplicateHandle(GetCurrentProcess(),hInputWriteTmp,
                        GetCurrentProcess(),
                        &hInputWrite, // Address of new handle.
                        0,FALSE, // Make it uninheritable.
                        DUPLICATE_SAME_ACCESS))
    DebugError("DupliateHandle");
 
 
    // Close inheritable copies of the handles you do not want to be
    // inherited.
    if (!CloseHandle(hOutputReadTmp)) DebugError("CloseHandle");
    if (!CloseHandle(hInputWriteTmp)) DebugError("CloseHandle");
 
 
    // Get std input handle so you can close it and force the ReadFile to
    // fail when you want the input thread to exit.
    if ( (hStdIn = GetStdHandle(STD_INPUT_HANDLE)) ==
                                            INVALID_HANDLE_VALUE )
        DebugError("GetStdHandle");
 
 
	hProc = PrepAndLaunchRedirectedChild(cmd,hOutputWrite,hInputRead,hErrorWrite,startDir);
	if(!hProc)
	{
		#ifdef _DEBUG
		printf("Shell: Error PrepAndLaunchRedirectChild\n");
		#endif
 
		return -1;
	}
 
    // 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.
    if (!CloseHandle(hOutputWrite)) DebugError("CloseHandle");
    if (!CloseHandle(hInputRead )) DebugError("CloseHandle");
    if (!CloseHandle(hErrorWrite)) DebugError("CloseHandle");
 
	if(1)  // != NULL)
	{
    // Launch the thread that gets the input and sends it to the child.
	hPipeWrite = hInputWrite;
//    hThread = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)GetAndSendInputThread,
//                            (LPVOID)hInputWrite,0,&ThreadId);
//TODO:  change to _createthread
    hThread = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)GetAndSendInputThread,
                            (LPVOID)this,0,&ThreadId);
 
	if (hThread == NULL) DebugError("CreateThread");
 
 
    // Read the child's output.
 
	str = "";
    ReadAndHandleOutput(hOutputRead);
	// Redirection is complete
	*outstr = str;
 
    // Force the read on the input to return by closing the stdin handle.
    //this is causing a problem.. so just ignore it and it will go away!
	if (!CloseHandle(hStdIn)) DebugError("CloseHandle");
 
 
    // Tell the thread to exit and wait for thread to die.
    bRunThread = FALSE;
 
    if (WaitForSingleObject(hThread,INFINITE) == WAIT_FAILED)
        DebugError("WaitForSingleObject");
 
    if (!CloseHandle(hOutputRead)) DebugError("CloseHandle");
    if (!CloseHandle(hInputWrite)) DebugError("CloseHandle");
	}
	ret = STILL_ACTIVE;
	do
	{
		Sleep(200);
		GetExitCodeProcess(hProc,&ret);
	}
	while(ret == STILL_ACTIVE);
 
	#ifdef _DEBUG
	printf("Shell: terminated properly\n");
	#endif
 
	return ret;
}
 
 
/////////////////////////////////////////////////////////////////////// 
// PrepAndLaunchRedirectedChild
// Sets up STARTUPINFO structure, and launches redirected child.
/////////////////////////////////////////////////////////////////////// 
HANDLE Shell::PrepAndLaunchRedirectedChild(char* cmd, HANDLE hChildStdOut,
                                    HANDLE hChildStdIn,
                                    HANDLE hChildStdErr, char* startDir)
{
    PROCESS_INFORMATION pi;
    STARTUPINFO si;
 
    // Set up the start up info struct.
    ZeroMemory(&si,sizeof(STARTUPINFO));
    si.cb = sizeof(STARTUPINFO);
    si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
    si.hStdOutput = hChildStdOut;
    si.hStdInput  = hChildStdIn;
    si.hStdError  = hChildStdErr;
    // Use this if you want to hide the child:
        si.wShowWindow = SW_HIDE;
    // Note that dwFlags must include STARTF_USESHOWWINDOW if you want to
    // use the wShowWindow flags.
 
 
    // Launch the process that you want to redirect (in this case,
    // Child.exe). Make sure Child.exe is in the same directory as
    // redirect.c launch redirect from a command line to prevent location
    // confusion.
//      if (!CreateProcess(NULL,"dir",NULL,NULL,TRUE,
//                         CREATE_NEW_CONSOLE,NULL,NULL,&si,&pi))
//         DebugError("CreateProcess");
 
	//LPTSTR szCmdline=TEXT("c:\\windows\\system32\\ipconfig.exe");
	SECURITY_ATTRIBUTES sa;
	//ZeroMemory(&sa,sizeof(SECURITY_ATTRIBUTES));
	sa.lpSecurityDescriptor = (PSECURITY_DESCRIPTOR) malloc(SECURITY_DESCRIPTOR_MIN_LENGTH);
	InitializeSecurityDescriptor(sa.lpSecurityDescriptor, PROCESS_QUERY_INFORMATION);
	SetSecurityDescriptorDacl(sa.lpSecurityDescriptor,TRUE,(PACL) NULL,FALSE);
	//sa.lpSecurityDescriptor = PROCESS_QUERY_INFORMATION;
	sa.bInheritHandle = 1;
	sa.nLength = sizeof(sa);
	char* startDirParam = startDir;
	if(startDir == 0)
		startDirParam = 0;
	else
	{
		if(strlen(startDir) == 0)  //strlen throws exception if startDir == 0
			startDirParam = 0;
	}
 
//	BOOL procCreated = CreateProcess(NULL, cmd, NULL, 0, 1, CREATE_NO_WINDOW, 0, startDirParam, &si, &pi);
	BOOL procCreated = CreateProcess(NULL, cmd, NULL, 0, 1, 0, 0, startDirParam, &si, &pi);
	if(!procCreated)
	{
		#ifdef _DEBUG
		CString debugStr;
 
		LPVOID lpMsgBuf;
		DWORD dw = GetLastError(); 
 
		FormatMessage(
			FORMAT_MESSAGE_ALLOCATE_BUFFER | 
			FORMAT_MESSAGE_FROM_SYSTEM |
			FORMAT_MESSAGE_IGNORE_INSERTS,
			NULL,
			dw,
			MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
			(LPTSTR) &lpMsgBuf,
			0, NULL );
 
		debugStr.Format("Shell CreateProc: %u, %s",dw,lpMsgBuf);
		OutputDebugString(debugStr.GetBuffer());
		printf("%s\n",debugStr.GetBuffer());
		#endif
	}
	delete sa.lpSecurityDescriptor;  //because of malloc
	if(!procCreated)
		DebugError("CreateProcess");
 
    // Set global child process handle to cause threads to exit.
    hChildProcess = pi.hProcess;
 
    // Close any unnecessary handles.
    if (!CloseHandle(pi.hThread)) DebugError("CloseHandle");
	return hChildProcess;
}
 
 
/////////////////////////////////////////////////////////////////////// 
// ReadAndHandleOutput
// Monitors handle for input. Exits when child exits or pipe breaks.
/////////////////////////////////////////////////////////////////////// 
void Shell::ReadAndHandleOutput(HANDLE hPipeRead)
{
    CHAR lpBuffer[256];
    DWORD nBytesRead;
 
    while(TRUE)
    {
		BOOL readS = ReadFile(hPipeRead,lpBuffer,sizeof(lpBuffer),
                                        &nBytesRead,NULL);
        if (!readS)
        {
        if (GetLastError() == ERROR_BROKEN_PIPE)
            break; // pipe done - normal exit path.
        else
            DebugError("ReadFile"); // Something bad happened.
        }
		str.append(lpBuffer,nBytesRead);
    }
}
 
 
/////////////////////////////////////////////////////////////////////// 
// GetAndSendInputThread
// Thread procedure that monitors the console for input and sends input
// to the child process through the input pipe.
// This thread ends when the child application exits.
/////////////////////////////////////////////////////////////////////// 
DWORD WINAPI GetAndSendInputThread(LPVOID lpvThreadParam)
{
    CHAR read_buff[256];
    DWORD nBytesRead,nBytesWrote;
    //HANDLE hPipeWrite = (HANDLE)lpvThreadParam;
	Shell* tthis = (Shell*)lpvThreadParam;
 
    // Get input from our console and send it to child through the pipe.
    while (tthis->bRunThread)
    {
		nBytesRead = 0;
		BOOL readS = ReadConsole(tthis->hStdIn,read_buff,1,&nBytesRead,NULL);
        if(!readS)
		{
			break;
        //DebugError("ReadConsole");
		}
 
        read_buff[nBytesRead] = '\0'; // Follow input with a NULL.
 
        if (!WriteFile(tthis->hPipeWrite,read_buff,nBytesRead,&nBytesWrote,NULL))
        {
        if (GetLastError() == ERROR_NO_DATA)
            break; // Pipe was closed (normal exit path).
        else
        tthis->DebugError("WriteFile");
        }
    }
 
    return 1;
}
 
void Shell::DebugError(char *pszAPI)
{
    LPVOID lpvMessageBuffer;
    CHAR szPrintBuffer[512];
 
    FormatMessage(
            FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
            NULL, GetLastError(),
            MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
            (LPTSTR)&lpvMessageBuffer, 0, NULL);
 
    wsprintf(szPrintBuffer,
        "ERROR: API    = %s.\n   error code = %d.\n   message    = %s.\n",
            pszAPI, GetLastError(), (char *)lpvMessageBuffer);
 
	OutputDebugString(szPrintBuffer);
 
    LocalFree(lpvMessageBuffer);
}
 
void Shell::ErrorExit(LPTSTR lpszFunction) 
{ 
    LPVOID lpMsgBuf;
    LPVOID lpDisplayBuf;
    DWORD dw = GetLastError(); 
 
    FormatMessage(
        FORMAT_MESSAGE_ALLOCATE_BUFFER | 
        FORMAT_MESSAGE_FROM_SYSTEM,
        NULL,
        dw,
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
        (LPTSTR) &lpMsgBuf,
        0, NULL );
 
    lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT, 
        (lstrlen((LPCTSTR)lpMsgBuf)+lstrlen((LPCTSTR)lpszFunction)+40)*sizeof(TCHAR)); 
    wsprintf((LPTSTR)lpDisplayBuf, 
        TEXT("%s failed with error %d: %s"), 
        lpszFunction, dw, lpMsgBuf); 
    MessageBox(NULL, (LPCTSTR)lpDisplayBuf, TEXT("Error"), MB_OK); 
 
    LocalFree(lpMsgBuf);
    LocalFree(lpDisplayBuf);
    ExitProcess(dw); 
}
Start your free trial to view this solution
Question Stats
Zone: Programming
Question Asked By: bowser17
Solution Provided By: bowser17
Participating Experts: 2
Solution Grade: A
Views: 130
Translate:
Loading Advertisement...
02.07.2008 at 03:19PM PST, ID: 20846423

Rank: Master

All comments and solutions are available to Premium Service Members only.

Start your 7-day free trial and see for yourself why Experts Exchange is the easiest and most proven technology resource in the world. Get Started

Already a member? Login to view this solution.

 
02.07.2008 at 03:25PM PST, ID: 20846468

All comments and solutions are available to Premium Service Members only.

Start your 7-day free trial and see for yourself why Experts Exchange is the easiest and most proven technology resource in the world. Get Started

Already a member? Login to view this solution.

 
02.08.2008 at 10:48AM PST, ID: 20852827

Rank: Master

All comments and solutions are available to Premium Service Members only.

Start your 7-day free trial and see for yourself why Experts Exchange is the easiest and most proven technology resource in the world. Get Started

Already a member? Login to view this solution.

 
02.08.2008 at 10:52AM PST, ID: 20852857

Rank: Genius

All comments and solutions are available to Premium Service Members only.

Start your 7-day free trial and see for yourself why Experts Exchange is the easiest and most proven technology resource in the world. Get Started

Already a member? Login to view this solution.

 
02.18.2008 at 07:34PM PST, ID: 20925501

All comments and solutions are available to Premium Service Members only.

Start your 7-day free trial and see for yourself why Experts Exchange is the easiest and most proven technology resource in the world. Get Started

Already a member? Login to view this solution.

 
02.20.2008 at 02:17PM PST, ID: 20942618

All comments and solutions are available to Premium Service Members only.

Start your 7-day free trial and see for yourself why Experts Exchange is the easiest and most proven technology resource in the world. Get Started

Already a member? Login to view this solution.

 
 
Loading Advertisement...
20080236-EE-VQP-29 / EE_QW_2_20070628