如何在使用Golang的Exec时隐藏命令提示窗口?

16

假设我有以下代码,使用syscall隐藏命令行窗口。

process := exec.Command(name, args...)
process.SysProcAttr = &syscall.SysProcAttr{HideWindow: true}
err := process.Start()
if err != nil {
    log.Print(err)
}

但是当我编译并在Windows上尝试运行它时,命令行窗口再次出现。

我该怎么做才能防止命令行窗口的出现?

PS:我已经知道如何将Golang源代码编译为Windows GUI可执行文件,使用go build -ldflags -H=windowsgui,但这样做只确保程序本身不会弹出命令行窗口,Exec仍然会显示这些窗口。


请问您能否更明确地说明您要隐藏哪个提示符? 您已经提到了正确的命令,可以同时隐藏Go命令行窗口和由exec生成的窗口。我目前最好的猜测是,您正在执行的命令会生成一个额外的窗口。 - Marco
也许可以,我将检查哪个命令会生成命令提示符(尽管很快就会消失)。 - jm33_m0
@jm33_m0 我刚试了一下你问题中提到的sysProcAttr方法,它确实有很大的改进——只有在Windows上会短暂地闪烁。你是否找到了完全防止闪烁的解决方案呢? - SwiftD
3个回答

27

这实际上回答了问题。谢谢! - Karel Bílek
但是,使用os.Getenv("windir")获取目录可能更安全。 - Karel Bílek
@KarelBílek 是的,但我还没有看到在Windows系统中cmd不在那个位置 :)。 - Yu Chen
我不知道该如何感谢你。自从昨天以来,我已经尝试了至少50种方法来隐藏这个终端窗口。我对终端窗口感到沮丧,甚至开始讨厌现实生活中的黑色。再次感谢你,你是我的救星。 - Sunil Kumar
构建时别忘了添加标志 go build -ldflags="-H windowsgui" main.go - Mike S

6

不要隐藏控制台窗口,你应该使用以下方法来防止它出现:

cmd := exec.Command(...)
cmd.SysProcAttr = &syscall.SysProcAttr{CreationFlags: 0x08000000} // CREATE_NO_WINDOW

这在Windows上似乎可以工作,但在WSL Ubuntu上编译时(使用旧版本的golang),我得到了csrc/sclaunch.go:759:42: unknown field 'CreationFlags' in struct literal of type syscall.SysProcAttr - philwalk
CreationFlags 只适用于 Windows,不适用于 Linux。 - Andrew McKinlay

5
如果使用-ldflags -H = windowsgui构建,则每个exec.Command将生成一个新的控制台窗口。
如果没有此标志,则只有一个控制台窗口,并且所有exec.Commands都会打印到该窗口中。
因此,我的当前解决方案是不使用该标志构建,即在程序启动时有一个控制台窗口,然后使用以下代码立即隐藏控制台窗口:
import "github.com/gonutz/w32/v2"

func hideConsole() {
    console := w32.GetConsoleWindow()
    if console == 0 {
        return // no console attached
    }
    // If this application is the process that created the console window, then
    // this program was not compiled with the -H=windowsgui flag and on start-up
    // it created a console along with the main application window. In this case
    // hide the console window.
    // See
    // https://dev59.com/yWox5IYBdhLWcg3wvWoy
    _, consoleProcID := w32.GetWindowThreadProcessId(console)
    if w32.GetCurrentProcessId() == consoleProcID {
        w32.ShowWindowAsync(console, w32.SW_HIDE)
    }
}

有关进程 ID 的详细信息,请参见此线程

现在,所有exec.Commands的输出都打印到隐藏的控制台窗口中,而不是生成自己的控制台窗口。

这里的妥协是,当您启动程序时,它会闪烁一次控制台窗口,但只会持续很短的时间,然后进入隐藏状态。


1
我之前只在win 7上遇到过这个问题,而不是8,但我刚刚在一台Windows 7机器上重新测试了一下,它确实像描述的那样工作 - 我不确定为什么之前尝试时会出现错误 - 已删除评论以避免混淆。答案已点赞,因为我现在将使用这种方法。 - SwiftD
同样相关:https://dev59.com/7HRB5IYBdhLWcg3w1Kr0#494000 - Christopher Oezbek

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接