最近工作中需要做一个开机自动启动其他应用的程序。并且要求可以设置是静默启动还是正常启动。这本来是一个比较常见的需求,如果用c++这种底层语言编写,只需要设置窗口属性为SW_HIDE就搞定了。但是公司要求用GO语言实现。虽然golang语言有提供windows系统包,但实际使用起来好像并不是那么好用(可能是自己没有使用好吧)。
网上有人说,隐藏调用的外部程序的cmd窗口,设置cmd属性,可以实现,代码如下:
cmd := exec.Command("cmd")
if runtime.GOOS == "windows" {
cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true}
}
经过多次尝试,没有达到项目需求,我需要寻找新的方法。
后来,我发现在上面exec.Command 参数里面添加start参数,可以显示启动程序,不添加start参数,就是静默启动(母程序本身静默启动)。代码如下:
func StartOtherApp(targetapp string, arg []string, bsilence bool) {
var temArg []string
temArg = append(temArg, "/c")
// 非静默启动,添加start参数
if !bsilence {
temArg = append(temArg, "start")
}
temArg = append(temArg, targetapp)
temArg = append(temArg, arg...)
cmd := exec.Command("cmd", temArg...)
cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: bsilence}
err := cmd.Run()
if nil != err {
fmt.Println(err)
lwlog.Logs.Error(fmt.Sprintf("start exe error:%v", err))
return
}
lwlog.Logs.Info(fmt.Sprintf("start exe:%s", targetapp))
fmt.Println("start exe:", targetapp)
}
这样,算是勉强达到需求吧!因为以上代码对带GUI程序是不生效的------不能隐藏GUI程序。虽然,项目上面没有隐藏GUI程序的需求,但是自己总感觉,不完美。
所以,我继续寻找可以隐藏GUI程序的方法。
经过查资料,发现powershell功能十分强大,可以隐藏启动外部程序。这让我十分高兴。
方案是这样的:
第一步,把powershell程序拉起来
第二步,给powershell传入执行参数。powershell支持Command参数,这个参数是“执行指定的命令,就好像他们是在windows powershell 命令提示符下键入的一样”,所以只需要把powershell 中隐藏程序的命令当参数传入即可。
好了,说完了解题思路,还是老规矩----贴上代码.
// 启动其他程序
// 参数1:targetapp,待启动程序路径+名称
// 参数2:arg,待启动程序传入参数
// 参数3:bsilence ,静默启动标识
func StartOtherApp(targetapp string, arg string, bsilence bool) {
var temArg []string
// 隐藏powershell窗口
temArg = append(temArg, "-WindowStyle")
temArg = append(temArg, "Hidden")
// 启动目标程序
temArg = append(temArg, "-Command")
temArg = append(temArg, "Start-Process")
temArg = append(temArg, targetapp)
// 目标程序参数
if len(arg) > 0 {
temArg = append(temArg, "-ArgumentList")
temArg = append(temArg, arg)
}
// 静默启动参数
if bsilence {
temArg = append(temArg, "-WindowStyle")
temArg = append(temArg, "Hidden")
}
cmd := exec.Command("PowerShell.exe", temArg...)
// 启动时隐藏powershell窗口,没有这句会闪一下powershell窗口
cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true}
err := cmd.Run()
if nil != err {
fmt.Println(err)
lwlog.Logs.Error(fmt.Sprintf("start exe error:%v", err))
return
}
lwlog.Logs.Info(fmt.Sprintf("start exe:%s", targetapp))
fmt.Println("start exe:", targetapp)
}
通过本次优化,可以达到隐藏大部分GUI程序了。有很少一部分程序,任然无法被隐藏。通过powershell都无法隐藏程序启动,它既然这么顽强,我们就放过它吧!
如果有朋友恰好需要这个功能,欢迎直接拷贝。