Go语言调用Windows SendMessageW函数无法返回的问题排查
问题原因及解决方案
问题根源
你使用的SendMessageW是Windows API中的阻塞式消息发送函数:它会将消息发送给目标窗口(这里是广播给所有顶层窗口0xFFFF),并等待所有接收窗口处理完消息后才会返回。如果系统中存在某个窗口未及时响应或处理该消息,你的程序就会一直卡在procSendMsg.Call()调用处,无法执行后续代码。
解决方案
改用非阻塞式的PostMessageW函数替代SendMessageW。PostMessageW仅将消息放入目标窗口的消息队列就立即返回,无需等待消息处理完成,完全避免了阻塞问题。
修改后的代码如下:
//go:build windows // +build windows package main import ( log "github.com/sirupsen/logrus" "golang.org/x/sys/windows" ) const ( WM_SYSCOMMAND = 0x0112 SC_MONITORPOWER = 0xF170 ) func main() { user32DLL := windows.NewLazyDLL("user32.dll") procPostMsg := user32DLL.NewProc("PostMessageW") // 使用windows.HWND_BROADCAST替代直接写0xFFFF,更符合规范 ret, _, err := procPostMsg.Call( uintptr(windows.HWND_BROADCAST), uintptr(WM_SYSCOMMAND), uintptr(SC_MONITORPOWER), uintptr(2), ) if ret == 0 { log.Errorf("PostMessage调用失败: %v", err) } else { log.Infof("消息发送成功,显示器已关闭") } }
补充说明
HWND_BROADCAST(值为0xFFFF)表示将消息广播给所有顶层窗口,使用windows.HWND_BROADCAST常量比直接写十六进制值更具可读性和规范性。SC_MONITORPOWER参数的取值:2代表关闭显示器,1代表打开显示器,-1代表将显示器切换到低功耗模式。- PowerShell中的
SendMessage调用看似正常返回,是因为.NET的P/Invoke封装在特定环境下未遇到阻塞窗口,但这并非通用可靠的实现方式,使用PostMessageW才是处理这类广播消息的正确姿势。
内容的提问来源于stack exchange,提问作者JD Allen
相关产品推荐
相关产品推荐

