Bug? - ReadProgramString() and unicode

Just starting out? Need help? Post your questions and find answers here.
c4s
Addict
Addict
Posts: 1981
Joined: Thu Nov 01, 2007 5:37 pm
Location: Germany

Bug? - ReadProgramString() and unicode

Post 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?
If any of you native English speakers have any suggestions for the above text, please let me know (via PM). Thanks!
User avatar
ts-soft
Always Here
Always Here
Posts: 5756
Joined: Thu Jun 24, 2004 2:44 pm
Location: Berlin - Germany

Re: Bug? - ReadProgramString() and unicode

Post by ts-soft »

Use ReadProgramData() and PeekS to read the string!
Justin
Addict
Addict
Posts: 948
Joined: Sat Apr 26, 2003 2:49 pm

Re: Bug? - ReadProgramString() and unicode

Post 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 
c4s
Addict
Addict
Posts: 1981
Joined: Thu Nov 01, 2007 5:37 pm
Location: Germany

Re: Bug? - ReadProgramString() and unicode

Post 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()?
If any of you native English speakers have any suggestions for the above text, please let me know (via PM). Thanks!
User avatar
ts-soft
Always Here
Always Here
Posts: 5756
Joined: Thu Jun 24, 2004 2:44 pm
Location: Berlin - Germany

Re: Bug? - ReadProgramString() and unicode

Post 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
Justin
Addict
Addict
Posts: 948
Joined: Sat Apr 26, 2003 2:49 pm

Re: Bug? - ReadProgramString() and unicode

Post 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
Last edited by Justin on Tue Apr 27, 2010 9:18 pm, edited 1 time in total.
c4s
Addict
Addict
Posts: 1981
Joined: Thu Nov 01, 2007 5:37 pm
Location: Germany

Re: Bug? - ReadProgramString() and unicode

Post 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:
If any of you native English speakers have any suggestions for the above text, please let me know (via PM). Thanks!
Justin
Addict
Addict
Posts: 948
Joined: Sat Apr 26, 2003 2:49 pm

Re: Bug? - ReadProgramString() and unicode

Post 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
Last edited by Justin on Tue Apr 27, 2010 9:19 pm, edited 1 time in total.
c4s
Addict
Addict
Posts: 1981
Joined: Thu Nov 01, 2007 5:37 pm
Location: Germany

Re: Bug? - ReadProgramString() and unicode

Post 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().)
If any of you native English speakers have any suggestions for the above text, please let me know (via PM). Thanks!
Justin
Addict
Addict
Posts: 948
Joined: Sat Apr 26, 2003 2:49 pm

Re: Bug? - ReadProgramString() and unicode

Post by Justin »

From wich program are you reading output?
c4s
Addict
Addict
Posts: 1981
Joined: Thu Nov 01, 2007 5:37 pm
Location: Germany

Re: Bug? - ReadProgramString() and unicode

Post by c4s »

It's LAME.exe (the mp3 encoder).
Well searching for enough characters (75) also does the job.
If any of you native English speakers have any suggestions for the above text, please let me know (via PM). Thanks!
Justin
Addict
Addict
Posts: 948
Joined: Sat Apr 26, 2003 2:49 pm

Re: Bug? - ReadProgramString() and unicode

Post 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.
c4s
Addict
Addict
Posts: 1981
Joined: Thu Nov 01, 2007 5:37 pm
Location: Germany

Re: Bug? - ReadProgramString() and unicode

Post 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
If any of you native English speakers have any suggestions for the above text, please let me know (via PM). Thanks!
Justin
Addict
Addict
Posts: 948
Joined: Sat Apr 26, 2003 2:49 pm

Re: Bug? - ReadProgramString() and unicode

Post 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
Last edited by Justin on Tue Apr 27, 2010 9:20 pm, edited 1 time in total.
c4s
Addict
Addict
Posts: 1981
Joined: Thu Nov 01, 2007 5:37 pm
Location: Germany

Re: Bug? - ReadProgramString() and unicode

Post 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()"?
If any of you native English speakers have any suggestions for the above text, please let me know (via PM). Thanks!
Post Reply