Page 1 of 2

Bug? - ReadProgramString() and unicode

Posted: Tue Apr 20, 2010 7:25 pm
by c4s
With unicode enabled the following example displays a big string instead of several ones. Test both modes to see what I mean. Code:

Code: Select all

Define ProgramString.s, ProgramNr


ProgramNr = RunProgram("help", "", GetPathPart(ProgramFilename()), #PB_Program_Open | #PB_Program_Read | #PB_Program_Hide)
If ProgramNr
	While ProgramRunning(ProgramNr)
		If AvailableProgramOutput(ProgramNr)
			ProgramString = ReadProgramString(ProgramNr)
			Debug ProgramString  ;; Bug? -> With unicode enabled just one big string
		EndIf
	Wend

	CloseProgram(ProgramNr)
EndIf
Is it a bug or am I doing something wrong?

Re: Bug? - ReadProgramString() and unicode

Posted: Tue Apr 20, 2010 8:01 pm
by ts-soft
Use ReadProgramData() and PeekS to read the string!

Re: Bug? - ReadProgramString() and unicode

Posted: Tue Apr 20, 2010 8:46 pm
by Justin
I did this function some time ago:

Code: Select all

procedure.s ReadProgramStringU(program)
	define.ASCII achar
	define.s text
	
	text = ""
  while ReadProgramData(program, @achar, sizeof(ASCII))
  	if achar\a = #CR
  		continue
  	
  	elseif achar\a = #LF
  		break
  	endif
  	
  	text = text + peeks(@achar, sizeof(ASCII), #PB_Ascii)
  wend 
  
  procedurereturn text
endprocedure 

Re: Bug? - ReadProgramString() and unicode

Posted: Tue Apr 20, 2010 9:04 pm
by c4s
Thanks, but I don't get it. This also doesn't work as expected because now several "lines" are in one:

Code: Select all

Define ProgramString.s, ProgramStringSize, ProgramNr


ProgramNr = RunProgram("help", "", GetPathPart(ProgramFilename()), #PB_Program_Open | #PB_Program_Read | #PB_Program_Hide)
If ProgramNr
	While ProgramRunning(ProgramNr)
		ProgramStringSize = AvailableProgramOutput(ProgramNr)
		If ProgramStringSize > 0
			ProgramString = Space(ProgramStringSize)
			ReadProgramData(ProgramNr, @ProgramString, ProgramStringSize)
			ProgramString = PeekS(@ProgramString, ProgramStringSize, #PB_Ascii)
			Debug ProgramString
		EndIf
	Wend

	CloseProgram(ProgramNr)
EndIf

Besides it seems that ReadProgramError() also doesn't work in unicode mode because trying a program where I should get some messages returns nothing (however in nonunicode mode everything is fine).


edit:
@Justin
Thank you, works perfectly. Do you have something similar for ReadProgramError()?

Re: Bug? - ReadProgramString() and unicode

Posted: Tue Apr 20, 2010 9:30 pm
by ts-soft
Not tested, but your code should like this:

Code: Select all

Define *ProgramStringbuffer, ProgramString.s,  ProgramStringSize, ProgramNr

ProgramNr = RunProgram("help", "", GetPathPart(ProgramFilename()), #PB_Program_Open | #PB_Program_Read | #PB_Program_Hide)
If ProgramNr
   While ProgramRunning(ProgramNr)
      ProgramStringSize = AvailableProgramOutput(ProgramNr)
      If ProgramStringSize > 0
         *ProgramStringbuffer = AllocateMemory(ProgramStringSize + 1)
         ReadProgramData(ProgramNr, *ProgramStringbuffer, ProgramStringSize)
         ProgramString + PeekS(*ProgramStringbuffer, -1, #PB_Ascii) + #LF$
         FreeMemory(*ProgramStringbuffer)
         Debug ProgramString
      EndIf
   Wend

   CloseProgram(ProgramNr)
EndIf

Re: Bug? - ReadProgramString() and unicode

Posted: Wed Apr 21, 2010 8:15 pm
by Justin
I did this include that works in ascii and unicode, it's based on an ols code i found by Rings. It reads the standard output and error, you can use #PROCESS_JOIN_OUTPUT to read everything at once.

Code: Select all

;process.pb
;Justin 04/10

enableexplicit

structure PROCESS_OBJ
	hReadStdOut.i
	hWriteStdOut.i
	hReadStdErr.i
	hWwriteStdErr.i
	process.PROCESS_INFORMATION
	dataRead.i
	lastErrChar.ASCII
	lastStdChar.ASCII
endstructure 

#PROCESS_JOIN_OUTPUT = 2 ;stdout and stderr are both redirected to the stdout pipe

declare.s proc__ReadLine(*lastChar.ASCII, *dataRead.i, hpipe.i)

;Public functions
procedure proc_RunProgram(program.s, commad.s, flags.l=0, *err.INTEGER=#null)
	define.PROCESS_OBJ *this
	define.STARTUPINFO start
	define.SECURITY_ATTRIBUTES sa
	define.i error
	
	*this = allocatememory(sizeof(PROCESS_OBJ))
	error = 0
	
  ;Create the Pipes
  sa\nLength =SizeOf(SECURITY_ATTRIBUTES)
  sa\bInheritHandle = 1 
  sa\lpSecurityDescriptor = 0 
  
  if CreatePipe_(@*this\hReadStdOut, @*this\hWriteStdOut, @sa, 0) 
  	if CreatePipe_(@*this\hReadStdErr, @*this\hWwriteStdErr, @sa, 0) 
  		start\cb = SizeOf(STARTUPINFO) 
  		start\dwFlags = #STARTF_USESHOWWINDOW | #STARTF_USESTDHANDLES 
  		start\hStdOutput = *this\hWriteStdOut 
  		if flags & #PROCESS_JOIN_OUTPUT = #PROCESS_JOIN_OUTPUT
  			start\hStdError = *this\hWriteStdOut 
  		else
  		  start\hStdError = *this\hWwriteStdErr 
  		endif 
  		
  		if CreateProcess_(0, program + " " + commad, @sa, @sa, 1, #NORMAL_PRIORITY_CLASS, 0, 0, @start, @*this\process) 
  			CloseHandle_(*this\hWriteStdOut) 
    		CloseHandle_(*this\hWwriteStdErr) 
  		
  		else ;CreateProcess error
  			error = -3
  		endif 
  	
  	else ;pipe error
  		error = -2
  	endif
  
  else ;pipe error
  	error = -1
  endif 
  
  if *err : *err\i = error : endif 
	
	if error=0
		procedurereturn *this
	
	else ;error
		CloseHandle_(*this\hReadStdErr) 
    CloseHandle_(*this\hReadStdOut) 
		CloseHandle_(*this\hWriteStdOut) 
    CloseHandle_(*this\hWwriteStdErr) 
		freememory(*this)
		procedurereturn #null
	endif
endprocedure

procedure proc_CloseProgram(*this.PROCESS_OBJ)
	CloseHandle_(*this\process\hProcess)
	CloseHandle_(*this\process\hThread)
	CloseHandle_(*this\hReadStdErr)
	CloseHandle_(*this\hReadStdOut)
	freememory(*this)
endprocedure 

macro proc_ReadStdOutLine(this)
	proc__ReadLine(@this\lastStdChar, @this\dataRead, this\hReadStdOut)
endmacro

macro proc_ReadStdErrLine(this)
	proc__ReadLine(@this\lastErrChar, @this\dataRead, this\hReadStdErr)
endmacro

procedure proc_GetExitCode(*this.PROCESS_OBJ)
	define.i exitCode
	
	if GetExitCodeProcess_(*this\process\hProcess, @exitCode)
		procedurereturn exitCode
	endif 
endprocedure 

macro proc_TerminateProcess(this, exitcode)
	TerminateProcess_(this\process\hProcess, exitcode)
endmacro

macro proc_DataRead(this)
	this\dataRead
endmacro

procedure.s proc__ReadLine(*lastChar.ASCII, *dataRead.INTEGER, hpipe.i)
   define.ASCII achar
   define.s text
   
  text = ""
  while ReadFile_(hpipe, @achar, sizeof(ASCII), *dataRead, 0)
		if achar\a = #CR 
			*lastChar\a = achar\a
			break
			
		elseif achar\a = #LF and *lastChar\a = #CR
			*lastChar\a = achar\a
			continue
 		endif
		
		text = text + peeks(@achar, sizeof(ASCII), #PB_Ascii)
		*lastChar\a = achar\a
  wend 
  
  procedurereturn text
endprocedure 

Code: Select all

;test
define.s program, cmd, line, text
define.PROCESS_OBJ *proc
define.i prog, counter

program = "c:\lame\lame.exe"
cmd = "--abr 30 --nohist --noreplaygain C:\test.mp3 C:\test_out.mp3"

*proc = proc_RunProgram(program, cmd, 0)
if *proc	
	counter = 1
	line = proc_ReadStdErrLine(*proc)
	while proc_DataRead(*proc)
		if counter=10
			proc_TerminateProcess(*proc, 100)
		endif 
		debug line

		line = proc_ReadStdErrLine(*proc)

		counter + 1
	wend
	
	debug proc_GetExitCode(*proc)
	
	proc_CloseProgram(*proc)
endif

Re: Bug? - ReadProgramString() and unicode

Posted: Wed Apr 21, 2010 9:09 pm
by c4s
Thanks Justin, I'll take a look at it.
Too bad there isn't an easier solution that uses native functions like ReadProgramData() or so.

edit:
Just did a small test and it doesn't seem to work.
Also I'm missing ProgramRunning() and ProgramExitCode().

edit2:
Ok, works...somehow. But ProgramExitCode() is still important for me. :wink:

Re: Bug? - ReadProgramString() and unicode

Posted: Wed Apr 21, 2010 11:52 pm
by Justin
There was a bug, when an empty line was found it stopped reading, so you have to use this new method for reading, i added proc_ExitCode() too.
I noticed that the PB process lib can't read the Microsoft mc.exe while these ones works.

edit:code removed use previous include

Re: Bug? - ReadProgramString() and unicode

Posted: Thu Apr 22, 2010 9:11 am
by c4s
Justin, thank you again!

So proc_DataRead() is like ProgramRunning()?

But still not fully satisfying: Now proc_ReadStdErrLine() returns just a big string. It seems like no #LF$ is found although the program normally returns many lines. :|


(I also could need KillProgram().)

Re: Bug? - ReadProgramString() and unicode

Posted: Sat Apr 24, 2010 10:45 pm
by Justin
From wich program are you reading output?

Re: Bug? - ReadProgramString() and unicode

Posted: Sun Apr 25, 2010 5:48 am
by c4s
It's LAME.exe (the mp3 encoder).
Well searching for enough characters (75) also does the job.

Re: Bug? - ReadProgramString() and unicode

Posted: Sun Apr 25, 2010 10:15 am
by Justin
It seems to work well here, although i just get one error line because i try to convert a non audio file. Is there a way to generate an error with several lines? And using --help works well too.

Re: Bug? - ReadProgramString() and unicode

Posted: Mon Apr 26, 2010 8:16 am
by c4s
Maybe it has to do something with the flags?
For the test I'm using:
--abr 30 --nohist --noreplaygain C:\test.mp3 C:\test_out.mp3
By the way: For ProgramRunning() I'm using this now:

Code: Select all

Procedure ProgramRunning2(*this.PROCESS_OBJ)
	Protected State
	Protected Result = #False

	If GetExitCodeProcess_(*this\process\hProcess, @State)
		If State = #STILL_ACTIVE
			Result = #True
		EndIf
	EndIf

	ProcedureReturn Result
EndProcedure

Re: Bug? - ReadProgramString() and unicode

Posted: Mon Apr 26, 2010 2:55 pm
by Justin
It seems the progress is shown in a single line although i have not test it, you can try this functions to split the line a show progress. it works here.

edit: code removed use previous include

Re: Bug? - ReadProgramString() and unicode

Posted: Mon Apr 26, 2010 4:07 pm
by c4s
Thanks, I will test it later.

The strange thing for me is that PureBasic is able to split it somehow even though #LF$ isn't send.


edit:
Ok, sure it works. But strange anyway.

Another small question: Does someone know how I can make my own "KillProgram()"?