Printing output to a command window when golang application is compiled with -ldflags -H=windowsgui

后端 未结 5 1767
野性不改
野性不改 2021-02-05 14:09

I have an application that usually runs silent in the background, so I compile it with

go build -ldflags -H=windowsgui 

To check

5条回答
  •  梦毁少年i
    2021-02-05 14:23

    The problem is that when a process is created using an executable which has the "subsystem" variable in its PE header set to "Windows", the process has its three standard handles closed and it is not associated with any console—no matter if you run it from the console or not. (In fact, if you run an executable which has its subsystem set to "console" not from a console, a console is forcibly created for that process and the process is attached to it—you usually see it as a console window popping up all of a sudden.)

    Hence, to print anything to the console from a GUI process on Windows you have to explicitly connect that process to the console which is attached to its parent process (if it has one), like explained here for instance. To do this, you call the AttachConsole API function. With Go, this can be done using the syscall package:

    package main
    
    import (
        "fmt"
        "syscall"
    )
    
    const (
        ATTACH_PARENT_PROCESS = ^uint32(0) // (DWORD)-1
    )
    
    var (
        modkernel32 = syscall.NewLazyDLL("kernel32.dll")
    
        procAttachConsole = modkernel32.NewProc("AttachConsole")
    
    )
    
    func AttachConsole(dwParentProcess uint32) (ok bool) {
        r0, _, _ := syscall.Syscall(procAttachConsole.Addr(), 1, uintptr(dwParentProcess), 0, 0)
        ok = bool(r0 != 0)
        return
    }
    
    func main() {
        ok := AttachConsole(ATTACH_PARENT_PROCESS)
        if ok {
            fmt.Println("Okay, attached")
        }
    }
    

    To be truly complete, when AttachConsole() fails, this code should probably take one of these two routes:

    • Call AllocConsole() to get its own console window created for it.

      It'd say this is pretty much useless for displaying version information as the process usually quits after printing it, and the resulting user experience will be a console window popping up and immediately disappearing; power users will get a hint that they should re-run the application from the console but mere mortals won't probably cope.

    • Post a GUI dialog displaying the same information.

      I think this is just what's needed: note that displaying help/usage messages in response to the user specifying some command-line argument is quite often mentally associated with the console, but this is not a dogma to follow: for instance, try running msiexec.exe /? at the console and see what happens.

提交回复
热议问题