How to get my own stdErr output?

Everything else that doesn't fall into one of the other PB categories.
User avatar
Kukulkan
Addict
Addict
Posts: 1422
Joined: Mon Jun 06, 2005 2:35 pm
Location: germany
Contact:

How to get my own stdErr output?

Post 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
freak
PureBasic Team
PureBasic Team
Posts: 5962
Joined: Fri Apr 25, 2003 5:21 pm
Location: Germany

Re: How to get my own stdErr output?

Post 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.
quidquid Latine dictum sit altum videtur
User avatar
Kukulkan
Addict
Addict
Posts: 1422
Joined: Mon Jun 06, 2005 2:35 pm
Location: germany
Contact:

Re: How to get my own stdErr output?

Post 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
freak
PureBasic Team
PureBasic Team
Posts: 5962
Joined: Fri Apr 25, 2003 5:21 pm
Location: Germany

Re: How to get my own stdErr output?

Post by freak »

Yes, but its more complex. You need threads to prevent a deadlock between the writing and reading of the stream then.
quidquid Latine dictum sit altum videtur
User avatar
Kukulkan
Addict
Addict
Posts: 1422
Joined: Mon Jun 06, 2005 2:35 pm
Location: germany
Contact:

Re: How to get my own stdErr output?

Post by Kukulkan »

I will try the file thing then... :wink:

Thank you!

Kukulkan
User avatar
skywalk
Addict
Addict
Posts: 4316
Joined: Wed Dec 23, 2009 10:14 pm
Location: Boston, MA

Re: How to get my own stdErr output?

Post 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.
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
User avatar
skywalk
Addict
Addict
Posts: 4316
Joined: Wed Dec 23, 2009 10:14 pm
Location: Boston, MA

Re: How to get my own stdErr output?

Post 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
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
Post Reply