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.)
因此,要从Windows上的GUI进程将任何内容打印到控制台,您必须显式地将该进程连接到附加到其父进程(如果它有父进程)的控制台,例如,如解释here所示.为此,您需要调用AttachConsole
API函数.对于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")
}
}
要真正完整,当AttachConsole()
失败时,此代码可能应该采取以下两种途径之一:
呼叫AllocConsole()
以获取为其创建的自己的控制台窗口.
它会说,这对于显示版本信息几乎毫无用处,因为这个过程通常会在打印后退出,由此产生的用户体验将是一个控制台窗口弹出并立即消失;超级用户会得到一个提示,他们应该从控制台重新运行应用程序,但仅仅是普通人可能无法应对.
发布一个显示相同信息的GUI对话框.
我认为这正是所需要的:请注意,显示帮助/用法消息以响应用户指定的一些命令行参数在控制台中通常是mentally associated,但这不是一个需要遵循的教条:例如,try 在控制台上运行msiexec.exe /?
,看看会发生什么.