Windows Binaries and stdout

1,093 views
Skip to first unread message

stephen.t....@gmail.com

unread,
Apr 25, 2022, 4:48:18 AM4/25/22
to golang-nuts
Hello,

I'm cross-compiling my Go application to Windows and I'm having difficulty understanding how Windows interacts with stdout.

I'm compiling the Windows binary with the "-H=windowsgui" LD flag. This works great but I've found that the program will never print to stdout, even if the program is launched from the command prompt

The alternative LD flag "-H=windows" will print to stdout but with the downside that a "DOS" window will always open, even if the program is launched from the desktop icon and even when there is no stdout activity.

For the most part, compiling with "-H=windowsgui" is fine but occasionally it's useful for users to run with the program's -log option, which outputs to stdout.

My solution for now is to have two Windows binaries. One for regular use and another for diagnosing problems. This is a poor solution.

What I require is a single binary that can:

1) Launch from the desktop icon without a "DOS" window opening.
2) To launch from a command prompt and for stdout to be echoed to the command prompt window.

Is there a Go compilation option that I've missed. Or is the solution more complex?

Regards

Stephen

stephen.t....@gmail.com

unread,
Apr 29, 2022, 3:34:29 AM4/29/22
to golang-nuts
I've read through my post again. I'll try to simplify my question:

Where is stdout for a Windows "GUI binary"? (see -H option)


If I run from the command prompt I would have thought that stdout is the console I'm running from but if the executable is a "GUI binary" this does not seem to be the case.

If I create a "console binary" then stdout is indeed the console I'm running from. But this means that when I run the binary from a desktop icon, Windows will open up a console window, even if there is nothing to output.

Context for this is an application that has a GUI by default and optionally, a terminal interface (using stdout).

I'm not a Windows person and I'm sorry if this is a dumb question but this is a complete mystery to me. Do I really need two separate binaries?

brainman

unread,
Apr 29, 2022, 4:33:47 AM4/29/22
to golang-nuts
Hello Stephen,

Windows uses special flag in every executable binary to determine if executable is a GUI or command line program.

go program uses "-H windows" linker flag to set that flag. See debug/pe.TestBuildingWindowsGUI for details.

Once windows executable is built, go has no control over how this program executes.

When command line program is executed by clicking in explorer window Windows automatically starts a new console window and the console is used for stdout output (I did not check that). If command line program is started from existing cmd.exe console, new process just uses the same console.

When you click on GUI executable in Windows explorer, no console windows is started (I did not check that). Same for GUI executable started from cmd.exe console - new GUI process is not attached to parent console (I did not check that).

If you want GUI with console window, you have to create console window in your code.

Alex 

Stephen Illingworth

unread,
Apr 29, 2022, 4:46:19 AM4/29/22
to golang-nuts
Hello Alex. Thanks for your response.

On Fri, Apr 29, 2022 at 9:34 AM brainman <alex.b...@gmail.com> wrote:
Once windows executable is built, go has no control over how this program executes.

When command line program is executed by clicking in explorer window Windows automatically starts a new console window and the console is used for stdout output (I did not check that). If command line program is started from existing cmd.exe console, new process just uses the same console.

When you click on GUI executable in Windows explorer, no console windows is started (I did not check that). Same for GUI executable started from cmd.exe console - new GUI process is not attached to parent console (I did not check that).

Right. So I have a GUI executable that might be launched from a console but it will not be "attached" to that parent console.

Is there a way to attach the GUI executable to the parent console, perhaps using a Windows system call?

jake...@gmail.com

unread,
Apr 29, 2022, 8:22:45 AM4/29/22
to golang-nuts
This is really a Windows issue, and not related to Go. According to this very old post: https://stackoverflow.com/questions/493536/can-one-executable-be-both-a-console-and-gui-application it is technically possible to do that, but the technique has flaws, foibles and limitations.

This sounds like a 'rabbit hole' to me. I would suggest going back to what you actually want to accomplish, and thinking about alternative ways of achieving it. 

stephen.t....@gmail.com

unread,
Apr 29, 2022, 8:47:06 AM4/29/22
to golang-nuts
You're right, it is a Windows issue. I can see that now. I bought up the issue originally because I was unsure if there was something in addition to -H=windows or -H=windowsgui that I could make use of. My understanding of Windows is now exhausted.

The alternative way is to have two binaries for the Windows version.

Anderson Queiroz

unread,
May 2, 2022, 9:27:22 AM5/2/22
to golang-nuts
You could log to a file. If you're willing to take in a -log flag, you could take a path as well and log to this file. That way you don't need 2 binaries, however you'd need to tail the file, which seems to me better than 2 binaries.

Best, 
Anderson

Robert Engels

unread,
May 2, 2022, 9:34:03 AM5/2/22
to Anderson Queiroz, golang-nuts

On May 2, 2022, at 8:27 AM, 'Anderson Queiroz' via golang-nuts <golan...@googlegroups.com> wrote:

You could log to a file. If you're willing to take in a -log flag, you could take a path as well and log to this file. That way you don't need 2 binaries, however you'd need to tail the file, which seems to me better than 2 binaries.
--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/95689cc2-ec6b-466f-ba3b-72a41756b328n%40googlegroups.com.

stephen.t....@gmail.com

unread,
May 5, 2022, 1:51:57 AM5/5/22
to golang-nuts
Yes. Logging to a file is probably the simplest option for this particular use case.

stephen.t....@gmail.com

unread,
May 5, 2022, 1:56:43 AM5/5/22
to golang-nuts
The blog is very interesting. However, I can't see how to re-implement this in Go with only the syscall package or the golang.org/x/sys/windows package. It needs the functionality of C++ freopen(), which as far as I can tell is not possible with the WinAPI - From what I can gather,  ReOpen() only works with file handles and not console handles returned by GetStdHandle().

Jason D

unread,
May 5, 2022, 7:49:51 PM5/5/22
to golang-nuts
It should be doable with just go code and the windows package..    CreateFile can do the same work that freopen is doing.

The CreateFile function enables a process to get a handle to its console's input buffer and active screen buffer, even if STDIN and STDOUT have been redirected. To open a handle to a console's input buffer, specify the CONIN$ value in a call to CreateFile. Specify the CONOUT$ value in a call to CreateFile to open a handle to a console's active screen buffer. CreateFile enables you to specify the read/write access of the handle that it return.

Reply all
Reply to author
Forward
0 new messages