使用-ldflags -H = windowsgui编译golang应用程序时,将输出打印到命令窗口

Bar*_*rim 13 go

我有一个通常在后台运行的应用程序,所以我用它编译它

go build -ldflags -H=windowsgui <gofile>
Run Code Online (Sandbox Code Playgroud)

要在命令行检查版本,我想将-V标志传递给命令行,以获取保存要打印到命令提示符的版本的字符串,然后让应用程序退出.我添加了标志包和代码.当我测试它时

go run <gofile> -V
Run Code Online (Sandbox Code Playgroud)

...打印版本很好.当我编译exe时,它只是退出,什么都不打印.我怀疑它是编译标志,导致它无法访问控制台并将我的文本发送到位桶.

我已尝试使用println和fprintf以及os.stderr.write打印到stderr和stdout的变体,但编译的应用程序中没有任何内容.在使用这些标志编译时,我应该如何尝试将字符串打印到命令提示符?

kos*_*tix 21

问题是当使用可执行文件创建进程时,其PE标头中的"子系统"变量设置为"Windows",该进程关闭了三个标准句柄,并且它与任何控制台无关 - 如果你是否从控制台运行它.(实际上,如果您运行的子系统设置为"控制台"的可执行文件不是来自控制台,则会强制为该进程创建一个控制台,并将该进程附加到该控制台上 - 您通常将其视为一个控制台窗口,弹出所有突然间.)

因此,要打印任何东西从Windows上的GUI程序,你必须是明确的流程连接到其连接到它的父进程(如果有的话)的控制台控制台,像解释这里的实例.为此,您可以调用AttachConsoleAPI函数.使用Go,可以使用syscall包完成:

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")
    }
}
Run Code Online (Sandbox Code Playgroud)

要真正完成,当AttachConsole()失败时,此代码应该采用以下两个路由之一:

  • 调用AllocConsole()为其创建自己的控制台窗口.

    它说这对于显示版本信息几乎没用,因为该过程通常在打印后退出,并且最终的用户体验将是一个控制台窗口弹出并立即消失; 高级用户会得到一个提示,他们应该从控制台重新运行应用程序,但凡人不会应对.

  • 发布显示相同信息的GUI对话框.

    我认为这仅仅是我们所需要的:请注意,以响应用户指定一些命令行参数往往显示帮助/用法消息精神上关联与控制台,但是这不是教条遵循:例如,尝试运行msiexec.exe /?在控制台,看看会发生什么.