Maybe it's an issue with the program I'm using, or just an issue overall, but using the streaming function does not really stream very well with a program that never stops running. As mentioned previous there is a large delay when running it with some console commands. I use windump (aka tcpdump) to parse incoming packets and it is delayed.
Further reading indicates that the delay in the stream is caused by buffering on the pipe as described in the solution I am using here:
http://www.codeproject.com/KB/threads/RTconsole.aspx
Here is an example of the solution I used. I hacked up the parsing in the CMDret_Stream function since it did not seem to work properly with my RTconsole solution. The changed CMDret_Stream code is included in the example.
Code:
;CMDret_Stream starts the command running. You only need these 3 lines to start the program.a
;Put all your main loop code in CMDret_Output which is the real main loop for this type of program.
sCmd = RTconsole.exe ping www.google.com
CMDret_Stream(sCmd)
Return
;All the processing on the returned text is done in the CMDret_Output section. CMDout is the lines returned.
;Use this as your "main" loop.
CMDret_Output(CMDout, CMDname="")
{
FileAppend, %CMDout%, *
Return
}
;CMDret_Stream function. Don't change unless you need to parse the returned information differently.
;Currently I parse it on every carriage return found. So each new line, roughly.
CMDret_Stream(CMDin, CMDname="", WorkingDir=0)
{
Global cmdretPID
tcWrk := WorkingDir=0 ? "Int" : "Str"
idltm := A_TickCount + 20
LivePos = 1
VarSetCapacity(CMDout, 1, 32)
VarSetCapacity(sui,68, 0)
VarSetCapacity(pi, 16, 0)
VarSetCapacity(pa, 12, 0)
Loop, 4 {
DllCall("RtlFillMemory", UInt,&pa+A_Index-1, UInt,1, UChar,12 >> 8*A_Index-8)
DllCall("RtlFillMemory", UInt,&pa+8+A_Index-1, UInt,1, UChar,1 >> 8*A_Index-8)
}
IF (DllCall("CreatePipe", "UInt*",hRead, "UInt*",hWrite, "UInt",&pa, "Int",0) <> 0) {
Loop, 4
DllCall("RtlFillMemory", UInt,&sui+A_Index-1, UInt,1, UChar,68 >> 8*A_Index-8)
DllCall("GetStartupInfo", "UInt", &sui)
Loop, 4 {
DllCall("RtlFillMemory", UInt,&sui+44+A_Index-1, UInt,1, UChar,257 >> 8*A_Index-8)
DllCall("RtlFillMemory", UInt,&sui+60+A_Index-1, UInt,1, UChar,hWrite >> 8*A_Index-8)
DllCall("RtlFillMemory", UInt,&sui+64+A_Index-1, UInt,1, UChar,hWrite >> 8*A_Index-8)
DllCall("RtlFillMemory", UInt,&sui+48+A_Index-1, UInt,1, UChar,0 >> 8*A_Index-8)
}
IF (DllCall("CreateProcess", Int,0, Str,CMDin, Int,0, Int,0, Int,1, "UInt",0, Int,0, tcWrk, WorkingDir, UInt,&sui, UInt,&pi) <> 0) {
Loop, 4
cmdretPID += *(&pi+8+A_Index-1) << 8*A_Index-8
Loop {
idltm2 := A_TickCount - idltm
If (idltm2 < 15) {
DllCall("Sleep", Int, 15)
Continue
}
IF (DllCall("PeekNamedPipe", "uint", hRead, "uint", 0, "uint", 0, "uint", 0, "uint*", bSize, "uint", 0 ) <> 0 ) {
Process, Exist, %cmdretPID%
IF (ErrorLevel OR bSize > 0) {
IF (bSize > 0) {
VarSetCapacity(lpBuffer, bSize+1, 0)
IF (DllCall("ReadFile", "UInt",hRead, "Str", lpBuffer, "Int",bSize, "UInt*",bRead, "Int",0) > 0) {
IF (bRead > 0) {
IF (StrLen(lpBuffer) < bRead) {
VarSetCapacity(CMcpy, bRead, 32)
bRead2 = %bRead%
Loop {
DllCall("RtlZeroMemory", "UInt", &CMcpy, Int, bRead)
NULLptr := StrLen(lpBuffer)
cpsize := bread - NULLptr
DllCall("RtlMoveMemory", "UInt", &CMcpy, "UInt", (&lpBuffer + NULLptr + 2), "Int", (cpsize - 1))
DllCall("RtlZeroMemory", "UInt", (&lpBuffer + NULLptr), Int, cpsize)
DllCall("RtlMoveMemory", "UInt", (&lpBuffer + NULLptr), "UInt", &CMcpy, "Int", cpsize)
bRead2 --
IF (StrLen(lpBuffer) > bRead2)
break
}
}
VarSetCapacity(lpBuffer, -1)
CMDout .= lpBuffer
;Uncomment the next line to look at the chunks of info read each time. They are fairly small.
;FileAppend, %lpbuffer%`n, *
bRead = 0
}
}
}
}
ELSE
break
}
ELSE
break
idltm := A_TickCount
;This is the part I changed. I just wait for a carriage return to be present...
;And then parse out each new line.
ifinstring, CMDout, `r
{
Loop, Parse, CMDout, `n
{
FileLine = %A_LoopField%
CMDret_Output(FileLine, CMDname)
}
CMDout =
}
}
cmdretPID=
DllCall("CloseHandle", UInt, hWrite)
DllCall("CloseHandle", UInt, hRead)
}
}
Loop, Parse, CMDout, `n
{
FileLine = %A_LoopField%
CMDret_Output(FileLine, CMDname)
}
cmdretPID = 0
Return, CMDout
}
From what I read, this type of reading from the console is not 100% reliable. Chances are you will be missing characters, etc. Chances are my new parsing section is also unreliable compounding the issue. Anyway, it works pretty reliably for me for what I need it to do. Maybe it will be of some use to someone in the future.