 |
|
 |
Hello
This is a class for C++ programmers.
But for all other programming languages this is not a solution.
If you came here because you are searching an easy way to capture the output of a Console application there is an easier way for you:
Have a look at the article CaptureConsole.dll.
The main features are:
1.) The coding is much easier for you: You don't have to implement a receiving Pipe in your main application.
2.) With two lines of code you call a console application invisibly, wait until it exits and get all its output and the Exit Code.
3.) All the funcionality is in a DLL, so it can be used in ANY project independent of the compiler: VB6, C++, .NET, Java, Delphi....
4.) You get stdout and stderr separated (optional)
5.) The DLL is thread save
6.) Timeout (optional)
7.) Codepage conversion
8.) Clean error handling
Elmü
|
|
|
|
 |
|
 |
HI
I tried to test the demo application with a console application. The console application is a third party software which writes data (double precision floats) to console in ASCII form. HOwever the problem was that console program writes 60 lines to console whereas the demo reads less than 50.
Can you tell me the reason and suggestion.
Thanx
|
|
|
|
 |
|
 |
Does anyone know how to add support to this class for early thread termination?? I could do some guess and check, but I don't have much Windows API experience
|
|
|
|
 |
|
 |
Shouldn't the line below in CSpawn::Redirect()
HANDLE hSaveStdout = GetStdHandle(STD_OUTPUT_HANDLE);
be:
m_hSaveStdout = GetStdHandle(STD_OUTPUT_HANDLE);
otherwise
if (!SetStdHandle(STD_OUTPUT_HANDLE,m_hSaveStdout))
would do nothing.
Hope this is helpful & thanks for the code.
John Curtis.
Software guy.
Fatlab Software.
|
|
|
|
 |
|
 |
Looks like you are right. Amazing that it took almost four years for this bug to be found :->
Leon[^] - Enterprise Anti-Spam Server
|
|
|
|
 |
|
 |
I have found a bug which can be duplicated when the child process has a delay between its stdout or stderr.
When there is a delay, the code checks whether the child process is still active by CSpawn::TestProcess. Because the function checks return value of GetExitCodeProcess instead of lpExitCode, CSpawn::ReadPipeThreadProc returns whether the child process is still running or not. Many people told about this before.
However, there was another problem.
Though the child process is already terminated, ReadFile does not return with the error code ERROR_BROKEN_PIPE. The reason is that the parent process also has both sides of handles of the pipes.
To fix the bug, close child side handles of pipes immediately after creating the child process. By doing it, we don't have to call PeekNamedPipe and GetExitCodeProcess. ReadFile will return an error. This is what Q190351[^] is doing.
And I think WaitForSingleObject (line 183) is unnecessary.
This is my spawn.cpp.[^]
|
|
|
|
 |
|
 |
Very good! This fix has solved my problems with the original Spawn.cpp (which is amazing, btw)
|
|
|
|
 |
|
 |
A good job!
but, fixed spawn.cpp can't be download now,
Could you send me a copy?
thank you very much!
my mail: joeasnake@hotmail.com
|
|
|
|
 |
|
 |
I am not able to download this bug fix. If anybody has it I would be very thankful if somebody could repost it.
-rlien
|
|
|
|
 |
|
 |
Hi guys --
I'm using CSpawn to communicate with several command-line applications. I'm running 65+ applications in a row, and analyzing the output.
Unfortunately I get random crashes! Sometimes it will happen on the first executable -- other times the entire sequence will run perfectly -- other times it will crash halfway through.
The crash occurs with the following error message:
First Chance Exception
Invalid Handle -- 0xC0000008
The problem appears to be in ReadPipeThreadProc, though I haven't been able to narrow it down very much. Can anyone provide a suggestion on what I need to do?
Thank you very much!
JP
|
|
|
|
 |
|
 |
Has anyone got this to sucessfully get multiline output. IM using "netsh interface ip show config"
which returns between 4-8 lines.
Anyone?
MM
|
|
|
|
 |
|
 |
The buffer is new-line agnostic -- here is what I added to my consumer class which allows me to parse the output on a line-by-line basis.
Note that this routine ignores the last line. You could check it in your destructor.
------------------
std::string prevLine;
virtual void Consume(TCHAR* output, DWORD dwChars) {
std::string workingString = output;
int newlinepos = workingString.find('\n');
while (newlinepos >= 0) {
prevLine += workingString.substr(0, newlinepos);
processLine(prevLine);
prevLine = "";
workingString.erase(0, newlinepos+1);
newlinepos = workingString.find("\n");
}
prevLine = workingString;
}
virtual void processLine(std::string line) = 0;
-------------------
Hope this helps,
JP
|
|
|
|
 |
|
 |
I use the class in a batch mode,every two m_Spawn.Execute() is very close in execution time. In your class,When the next command come, the previous one's read thread would be killed, so no stdout would be caught,how can I deal with it? I try to use a event handle, let Execute() WaitForSingleObject() in its if statement, and put a SetEvent() before ReadPipeThreadProc() returns.But by doing so, Execute() will keep on waiting. As if the read thread never get a chance to run.
How can I figure it out?
Any help will be appreciated!
|
|
|
|
 |
|
 |
Hi,
My intention is to use an exe program called cbird.exe in my application.
I need to interact this program by giving it some inputs and reading its output.
CSpawn class seems useful. Can some body give me start by providing two lines (may be more) code of creating a child process for cbird.exe and how to interact with it...I am able to understand the CSpawn class itself, but kind of not able to understand the way it is used in the demo project.
Thanks a lot in advance.
jim
learning to learn is the best education
|
|
|
|
 |
|
 |
ASSERT(m_pReadThread == NULL);
m_pReadThread = AfxBeginThread((AFX_THREADPROC)ReadPipeThreadProc, (LPVOID)this, THREAD_PRIORITY_BELOW_NORMAL);
if (!m_pReadThread)
{
throw(_T("Cannot start read-redirect thread!\n"));
}
// Now create the child process.
if (! CreateChildProcess())
Should be:
ASSERT(m_pReadThread == NULL);
m_pReadThread = AfxBeginThread((AFX_THREADPROC)ReadPipeThreadProc, (LPVOID)this, THREAD_PRIORITY_BELOW_NORMAL,0,CREATE_SUSPENDED,NULL);
// Need to create suspended so we can turn off
// auto deletion
if (!m_pReadThread)
{
throw(_T("Cannot start read-redirect thread!\n"));
}
// Need to turn off auto deletion because we are handle deleting ourselves
m_pReadThread->m_bAutoDelete = FALSE;
// Now create the child process.
if (! CreateChildProcess())
Otherwise thanks for the code.
-Michael O. Schoneman
|
|
|
|
 |
|
 |
I am trying to run .cmd files from this class and am unable to do so. Any ideas?
All help is appreciated. Congratulations on a great class -- very helpful!
-Dharmesh
|
|
|
|
 |
|
 |
In TestProcess, the call to GetExitCodeProcess to see if the process is STILL_ACTIVE always returns true. The check should be dwExitCode == STILL_ACTIVE. Otherwise, the pipe is closed too soon.
bool CSpawn::TestProcess()
{
if (m_dwProcessId != DWORD(-1))
{
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, m_dwProcessId);
if (hProcess)
{
DWORD dwExitCode;
BOOL bRet = GetExitCodeProcess(hProcess, &dwExitCode); // fails when the process is active
VERIFY(CloseHandle(hProcess));
return dwExitCode == STILL_ACTIVE;
}
}
return FALSE;
}
Donald
|
|
|
|
 |
|
 |
Hi,
thanks for the code.
I have a question. Within your sample application I called an app that just prints out a status message every second. I couldn´t see anything in your application. But after the app I called has ended there was the output but all at once. When I call the app within a DOS console I can see the output every second.
Do you know how to get the output immediately ?
Thanks
|
|
|
|
 |
|
 |
This is probably related to the way it reads the in-stream. If the buffer is full, it processes the content. If an application sends less then the read will wait until the buffer is full.
Try modifying the buffer size.
Shaken, stirred, or strained through a diaper, nothing can make a martini palatable. Roger Wright, Soapbox
|
|
|
|
 |
|
 |
Within the client application, call 'fflush()' to force a buffer flush after each output.
If you're outputting (or inputting from file) large quantities of data (you don't seem to be, from your description), this will cause a performance hit.
|
|
|
|
 |
|
 |
How do I have to use SendInput???? I have absolutely no Idea. I would be very nice, if someone could give my a little sample. Just the pessage where SendInput is called
Thx
|
|
|
|
 |
|
 |
You create an array of INPUT structures fill them with whatever events you want to send and pass it to SendInput().
This question doesnt belong to this article, does it? Ok, ask it again in the Visual C++ Forum[^].
...if you're under 8 or younger. Chris Maunder, the Lounge
|
|
|
|
 |
|
 |
Hello,
First, -- thank you for creating this class. It has been very helpful.
However, I'm running into random crashes inside the ReadPipeThreadProc routine. The crash is:
Invalid Handle -- Exception 0xC0000008
Have you run into these? I can't narrow down the cause.
I am running 65+ applications in a row and analyzing the output. It happens randomly, but usually about halfway through my set of executions.
Any ideas on how to make the routine scalable?
Thanks,
JP
|
|
|
|
 |
|
 |
If i use the CSpawn class with just a generic process that dumps to stdout all is fine (again congrats on the class). However if I use it with a process that spits stuff out to stdout, and ALSO spawns off other process(s), I get some of the output but then the read thread dies off early(? I am guessing here) and I don't get the rest of the output.
Any thoughts ? Are there some flags for CreateProcess in the CreateChildProcess() method that need ot be used ?
Thanks
|
|
|
|
 |
|
 |
I suppose it has to do with handle inheritance and how the application spawns its childs. As for the CSPawn class, all flags are set correctly.
When you try to use it over multiple instances of spawned applications you are more or less out of luck with "normal" methods. You have no control over the 2nd generation anymore.
...make it about Visual C++, and don't ever mention Visual Basic. Nick Hodapp (MSFT) in Semicolon[^]
|
|
|
|
 |