Page 1 of 1

How to get my own stdErr output?

Posted: Thu Sep 26, 2013 2:50 pm
by Kukulkan
Hello,

I'm calling a foreign DLL/dylib (Win + Mac) which outputs errors to stdErr. Sadly, I dont know how to get the output.

ReadProgramError() only works with a program parameter which I do not have (because it is my own running process).

Any idea how to get the stdErr of the DLL in my own process?

Thank you,

Kukulkan

Re: How to get my own stdErr output?

Posted: Thu Sep 26, 2013 7:23 pm
by freak
It is possible to redirect it to a file. The following code works on Windows:

Code: Select all

; Create file for redirection
CreateFile(0, "test.txt")

; Replace the standard error handle with the created file
oldHandle = GetStdHandle_(#STD_ERROR_HANDLE)
SetStdHandle_(#STD_ERROR_HANDLE, FileID(0))

; do some output
OpenConsole()
For i = 1 To 10
  ConsoleError("StdErr Message" + i)
Next i
CloseConsole()

; restore original handle
SetStdHandle_(#STD_ERROR_HANDLE, oldHandle)

; close file
CloseFile(0)
Note that you should do the replacing of the handle before you load your dll, because it may be possible that the dll reads and stores the handle somewhere in a variable in which case changing the standard handle after that will have no effect. For example in PB, after OpenConsole() is called, changing the handle has no effect anymore because the console lib stores the handle in its own variable.

A similar thing should be possible on OSX by importing the "stderr" variable and changing it. Note that I did not try the code below as I don't have OSX available right now. The variable could also be named "_stderr" or similar on OSX. You may have to do a bit trial & error there:

Code: Select all

ImportC ""
  stderr.i
EndImport


; Create file for redirection
CreateFile(0, "test.txt")

; Replace the standard error handle with the created file
oldStdErr = stderr
stderr = FileID(0)

; do some output
OpenConsole()
For i = 1 To 10
  ConsoleError("StdErr Message" + i)
Next i
CloseConsole()

; restore original handle
stderr = oldStrErr

; close file
CloseFile(0)
It is also possible to redirect to a pipe so no file is needed, but this is more complex because you have to read from the pipe at the same time that the dll writes to it (or the program will lock up) which would require using threads. If redirecting to a file is enough then this is definitely the simpler solution.

Re: How to get my own stdErr output?

Posted: Fri Sep 27, 2013 6:21 am
by Kukulkan
Hello freak,

thank you very much! Indeed, this seems a solution.

Do you think it is possible to use something "in memory" instead of using a file? Maybe some "memory writer" output?

Kukulkan

Re: How to get my own stdErr output?

Posted: Fri Sep 27, 2013 3:18 pm
by freak
Yes, but its more complex. You need threads to prevent a deadlock between the writing and reading of the stream then.

Re: How to get my own stdErr output?

Posted: Fri Sep 27, 2013 4:16 pm
by Kukulkan
I will try the file thing then... :wink:

Thank you!

Kukulkan

Re: How to get my own stdErr output?

Posted: Sat Oct 19, 2013 11:47 pm
by skywalk
I thought to post here since freak's suggested code sounds like a fit?
I use fossil.exe in a cmd prompt as my SCM and for a failed commit it outputs an error to the console.

Code: Select all

c:\tryfossil>fossil commit --user me -M commit.txt
nothing has changed; use --allow-empty to override
If I try to pipe that message to a file so I can read it in code it creates an empty file and spits the error out as before.

Code: Select all

c:\tryfossil>fossil commit --user me -M commit.txt > fossilout.txt
nothing has changed; use --allow-empty to override
If I try freak's code above, I also get nothing.

My point for all this is to automate some repetitive steps and handle errors. However, I cannot get the error returned from this command?

Code: Select all

rp = RunProgram("fossil.exe", "commit --user me -M c:\tryfossil\commit.txt", "c:\tryfossil\", #PB_Program_Open | #PB_Program_Read | #PB_Program_Hide)
Indirectly I can prevent this error by asking fossil if there is anything to commit. But, this inability to read the output worries me for future commands.

Re: How to get my own stdErr output?

Posted: Sun Oct 20, 2013 1:34 am
by skywalk
Never mind, another case of RTFM! Didn't see ReadProgramError() :oops:

Code: Select all

rp = RunProgram("cmd.exe", "/c fossil.exe commit --no-warnings --user me -M " + *r\Path$ + #fos_commit$, *r\Path$, #PB_Program_Open | #PB_Program_Read | #PB_Program_Error | #PB_Program_Hide)
If rp
  *r\e$ = #NULL$
  *r\e$ = ReadProgramError(rp)
EndIf