go编译命令回顾
go build -o tool.exe 会将当前目录下的main文件编译为tool.exe可执行文件
:: 无界面编译: go build -ldflags=“-w -s -H windowsgui” -o tool.exe
:: 常规编译(-ldflags=“-w -s” 用于去除调试信息) go build -ldflags=“-w -s” -o tool.exe
问题描述:
golang开发的windows工具打包成exe可执行文件,并且编译时选择显示控制台实时打印(即有界面编译),但是用户会不经意间光标选中控制台打印窗口,导致服务暂停运行,用户光标在控制台窗口区域,按下回车键才能继续运行。
原始代码示例:
package main
import (
"fmt"
"time"
)
func main() {
// 在控制台输出一些测试信息
for i := 1; i <= 10; i++ {
fmt.Printf("第 %d 行\n", i)
time.Sleep(time.Second * 2)
}
// 编译成.exe文件命令: go build tool.go
}
问题现象:
解决方案:
要解决用户不小心选中控制台窗口导致程序暂停运行的问题,可以在 Windows 控制台下使用 SetConsoleMode 函数来设置控制台输入模式,禁止控制台窗口的鼠标选择功能。
在 Windows 平台上,可以使用 golang.org/x/sys/windows 包来调用 Win32 API,该包提供了一组 Windows 系统调用的 Go 接口
go get golang.org/x/sys/windows
以下是示例代码:
package main
import (
"fmt"
"golang.org/x/sys/windows"
"time"
)
const ENABLE_QUICK_EDIT_MODE = 0x0040
// ForbiddenConsoleEdit 禁止控制台窗口的鼠标选择功能
func ForbiddenConsoleEdit() error {
hConsole, err := windows.GetStdHandle(windows.STD_INPUT_HANDLE)
if err == nil {
mode := uint32(0)
err = windows.GetConsoleMode(hConsole, &mode)
if err == nil {
mode &^= ENABLE_QUICK_EDIT_MODE
if err := windows.SetConsoleMode(hConsole, mode); err != nil {
return err
} else {
return nil
}
} else {
return err
}
} else {
return err
}
}
func main() {
// 禁止控制台窗口的鼠标选择功能(鼠标点击控制器或选择控制台打印的内容,会暂停程序运行,鼠标移开程序才能继续运行)
if err := ForbiddenConsoleEdit(); err != nil {
fmt.Println("设置失败", err.Error())
} else {
fmt.Println("设置成功")
}
// 在控制台输出一些测试信息
for i := 1; i <= 10; i++ {
fmt.Printf("第 %d 行\n", i)
time.Sleep(time.Second * 2)
}
// 编译成.exe文件命令: go build tool.go
}
解释:
在示例代码中,我们首先使用 syscall.Open 函数打开 Windows 控制台设备文件 “CONIN$”,并获取其句柄 hConsole。然后,通过 GetConsoleMode 函数获取控制台的输入模式,再通过位运算去除控制台的快速编辑模式(即双击鼠标选择文本的功能),最后通过 SetConsoleMode 函数更新控制台输入模式。
这样,在程序运行期间,用户就无法使用鼠标选择控制台窗口中的文本了,从而避免了不经意间导致程序暂停运行的问题。