How do you get pub.freeprocess to read i/o ??

BlitzMax Forums/BlitzMax Programming/How do you get pub.freeprocess to read i/o ??

skn3(Posted 2007) [#1]
What am I doing wrong here ?

Firstly, how do I get it to open the process silently.

Secondly, how do I get the process input / ouput ?

I tried reading from both the pipes but nothing works.

Any help ?

Framework brl.standardio
Import pub.freeprocess

Local temp_process:TProcess = CreateProcess("cmd.exe /c ~qipconfig~q")
Local temp_read:String

Print "started"
While temp_process.status()
	temp_read = temp_process.pipe.readline()
	Print "read = @"+temp_read+"@"
Wend
temp_process.close()
temp_process.terminate()
temp_process = Null
Print "ended"



SebHoll(Posted 2007) [#2]
Hi,

First of all, because "ipconfig" is a program in its own right, you don't need to open it with a command prompt. If you wanted to run it manually to check an IP, you would have to use the command prompt as you need a program to catch and display ipconfig's output, however as your program is supposed to catch the output instead, you don't need it.

Working example :-( Found not to work in most cases - scroll down to later posts for a working version!



Also, you may want to note that all processes you run are terminated when your blitz app ends, so no need to add this manually (notice the use on OnEnd at the bottom of freeprocess.bmx).

The thing to remember is that the pipe field of TProcess can basically be read from and written to exactly like any other stream, as it extends TStream.

Hope this helps,


Seb


skn3(Posted 2007) [#3]
Thanks for the help seb,

This is where im having strange issues. Your example (and myn) dont capture anything. The only thing i get from your example is shown below.

Any ideas ?

IPConfig Status: 1
================================

================================
IPConfig Status: 0


... ?


SebHoll(Posted 2007) [#4]
That's strange... :S

I get the following output with my example:



What OS are you using? Also, what are the contents of C:\ipconfig.txt when you run ipconfig > "C:\ipconfig.txt" in the Command prompt normally.


skn3(Posted 2007) [#5]
My work computer (which im testing this on) is running..

XP pro v 2002 srv pack 2


Windows IP Configuration





Ethernet adapter Local Area Connection:



Connection-specific DNS Suffix . :

IP Address. . . . . . . . . . . . : 10.0.0.42

Subnet Mask . . . . . . . . . . . : 255.255.255.0

Default Gateway . . . . . . . . . : 10.0.0.201



tonyg(Posted 2007) [#6]
If it helps... I don't get any output either on W2K.


SebHoll(Posted 2007) [#7]
I'm running Vista and it seems to work fine. I think it might be that the IpConfig terminates immediately after it has output the data, and Pub.FreeProcess won't read anymore data from the stream if the process isn't "alive".

The reason for me saying this is that although when I run it, it output information, it is cutting off more lines that you would normally get from the console. Maybe because you have super fast computers, it's cutting it off before it even get's going... Whereas I have loads of virtual adapters on my Vista box that take longer to output.

Does this give you any better results? Can you post your output?




SebHoll(Posted 2007) [#8]
Multiple post deleted. Please remove.


SebHoll(Posted 2007) [#9]
Multiple post deleted. Please remove.


SebHoll(Posted 2007) [#10]
Multiple post deleted. Please remove.


SebHoll(Posted 2007) [#11]
Multiple post deleted. Please remove.


SebHoll(Posted 2007) [#12]
Multiple post deleted. Please remove.


SebHoll(Posted 2007) [#13]
Multiple post deleted. Please remove.


SebHoll(Posted 2007) [#14]
Multiple post deleted. Please remove.


SebHoll(Posted 2007) [#15]
Multiple post deleted. Please remove.


grable(Posted 2007) [#16]
It doesn't print anything here either (XP).

Your second example does work though.
I also had another example using a TTextStream wrapping the Pipe stream, which also works.

Just too bad both methods freeze for 10-15 seconds before there is any output :/

EDIT: maybe vista is the source of your "multiple post" problem as well? ;) hehe


SebHoll(Posted 2007) [#17]
LOL - that's really strange. I just posted like I normally do! Hopefully a moderator can clean this little problem up.

Anyways, I think the pause could be partly because of the fact that IpConfig seems to output it's title, then gather the info, then output it, and depending on your hardware, it can take a few seconds delay.

However, my second method works fine on my end too. I think the idea is to grab all the data that's available when you loop (using ReadPipe() ) as oppose to line by line as it's slower.

Also, there is a inbuilt function that converts byte arrays into string, so the whole process can be done on one line:




skn3(Posted 2007) [#18]
Your example now works.

Now try this:
SuperStrict

Framework brl.standardio
Import pub.freeprocess

?Win32

	'Lets use OO for the hell of it, although you can use CreateProcess() if you prefer
	'There is only 1 flag available - HIDECONSOLE that is supposed to hide console output ;-) but it doesn't make much difference either way on my Windows machine
	Local temp_process:TProcess = TProcess.Create("net start THIS_SERVICE_DOESNT_EXIST",HIDECONSOLE)
	
	Print ""
	Print "IPConfig Status: " + temp_process.Status()	'Show that the program is running
	Print "================================"
	
	While temp_process.Status()	'Checks to see if the process is still running
		
		'Temp variable that stores output from the pipe before it is converted to a string
		Local tmpBytes:Byte[]
		'Check if the pipe contains any data that hasn't been read and if so, load data into variable array, and convert array to string
		If temp_process.pipe.ReadAvail() Then tmpBytes = temp_process.pipe.ReadPipe();Print String.FromBytes( Varptr tmpBytes[0], tmpBytes.length )
		
	Wend
	

		
	'Terminate process manually (the fact that is has escaped the above loop means it has already closed but put it in as an example)
	temp_process.Close()
	'This is a quick way you can terminate all processes without bothering to loop through them all (again not needed)
	TProcess.TerminateAll()
	
	Print "================================"
	Print "IPConfig Status: " + temp_process.Status()	'Show that the program has ended
	Print ""

?MacOs

	Print "Mac OS X doesn't have IpConfig."

?Linux

	Print "Linux doesn't have IpConfig."

?


Why does this not work ???


SebHoll(Posted 2007) [#19]
Aha! - What you have here is that net.exe wants to output an error, so instead of writing to the normal pipe stream, it outputs to a dedicated error pipe stream... This error stream can be used in exactly the same way as term_process.pipe, except it's term_process.err:



Notice the additional line I've added to catch error messages! It's useful that you can separate out error messages from standard output without even having to parse - usually if a process outputs there then this is an important error that would affect the normal output and it can be identified immediately.

Sorry I forgot to mention this, I don't think there is anything else you have to look out for.

;-)


skn3(Posted 2007) [#20]
You sir are a star!

Brill! Saved me some headaches at work tommorow!

I think we need to pertition for this to be added to the docs :)


tonyg(Posted 2007) [#21]
Yep, thanks Seb. Been following this and very informative.


SebHoll(Posted 2007) [#22]
No probs! Glad I can be of some help to someone on these forums! It's usually me asking all the questions. ;-)


DJWoodgate(Posted 2007) [#23]
Yes, Thanks are due. I think I understand the Readline method a bit better now. (At first I thought it was completely borked, shame on me!). It is non blocking, and sits in front of a 4k buffer. In this case pretty much all the output from these commands is available at once unless as you say it is a slow machine or a lot is going on, so it is buffered immediately and readline starts to work on the buffer, but by that time the process has finished.

Fortunately Bufferpos is exposed as a field in TPipeStream so you can check that.

SuperStrict

Framework brl.standardio
Import pub.freeprocess

Local temp_process:TProcess = CreateProcess("ipconfig /?",HIDECONSOLE)
Local temp_read:String, avail:Int

Print "started"
Repeat
	' loop until data available.  In practice of course you would be doing other things.
	Repeat 
		avail = temp_process.pipe.readavail()
		If temp_process.status()=0 Then Exit
	Until avail>0

	Print "Status "+temp_process.status()
	Print "Avail "+avail
 	
	If avail=0 Then Exit

	' get available data
	Repeat
			temp_read  = temp_process.pipe.readline()

			Print temp_process.pipe.bufferpos +" read >"+temp_read

	Until temp_process.pipe.bufferpos<=0
Forever
temp_process.close()
temp_process.terminate()
temp_process = Null
Print "ended"



skn3(Posted 2007) [#24]
How about this then ,with thanks from all!

Import pub.freeprocess

Type tproc Extends TProcess
	Method close:Int()
		super.close()
		terminate()
	End Method

	Method avail:Int()
		Return err.bufferpos Or err.readavail() Or pipe.bufferpos Or pipe.readavail()
	End Method
	
	Method read:String()
		If err.bufferpos > 0 Or err.readavail() > 0 Return err.ReadLine().Replace("~r","").Replace("~n","")
		If pipe.bufferpos > 0 Or pipe.readavail() > 0 Return pipe.ReadLine().Replace("~r","").Replace("~n","")
	End Method

	Method readpipe:String()
		If pipe.bufferpos > 0 Or pipe.readavail() > 0 Return pipe.ReadLine().Replace("~r","").Replace("~n","")
	End Method
	
	Method readerr:String()
		If err.bufferpos > 0 Or err.readavail() > 0 Return err.ReadLine().Replace("~r","").Replace("~n","")
	End Method
	
	Method pipeavail:Int()
		Return pipe.bufferpos Or pipe.readavail()
	End Method
	
	Method erravail:Int()
		Return err.bufferpos Or err.readavail()
	End Method
	
	Method Eof:Int()
		If status() = 1 Return False
		If pipe.readavail() > 0 Return False
		If err.readavail() > 0 Return False
		If pipe.bufferpos > 0 Return False
		If err.bufferpos > 0 Return False
		Return True
	End Method

	Function Create:TProc(ncmd:String,nflags:Int)
		Local temp_proc:TProc
		Local infd,outfd,errfd	
		
		'do mac speciffic stuff
		?MacOS
		If FileType(ncmd)=2
			ncmd :+ "/Contents/MacOS/" + StripExt(StripDir(ncmd))
		EndIf
		?
		
		'create the proc object
		temp_proc = New TProc
		
		'setup the proc
		temp_proc.name = ncmd
		
		'attempt to start the process
		temp_proc.handle = fdProcess(ncmd,Varptr(infd),Varptr(outfd),Varptr(errfd),nflags)
		If Not temp_proc.handle Return Null
		
		'creat teh process pipes
		temp_proc.pipe = TPipeStream.Create(infd,outfd)
		temp_proc.err = TPipeStream.Create(errfd,0)
		
		'add process to process list
		If Not ProcessList ProcessList = New TList
		ProcessList.AddLast temp_proc
		
		'return the proc object
		Return temp_proc
	End Function
End Type

Function CreateProc:tproc(ncmd:String,nhidden:Int = True)
	Return tproc.create(ncmd,nhidden)
End Function


Example 1:
Local temp_proc:tproc = CreateProc("net start MOO_MOO_MOO")
While temp_proc.eof() = False
	If temp_proc.avail() Print "read: " + temp_proc.read()
Wend
temp_proc.close()


Example 2:
Local temp_proc:tproc = CreateProc("net start MOO_MOO_MOO")
While temp_proc.eof() = False
	If temp_proc.pipeavail() Print "pipe: " + temp_proc.readpipe()
	If temp_proc.erravail() Print "err: " + temp_proc.readerr()
Wend
temp_proc.close()



DJWoodgate(Posted 2007) [#25]
Looks good. You have even implemented the missing EOF method. One for the code archives.