feat: 增强桌面启动失败提示与测试覆盖
This commit is contained in:
@@ -3,17 +3,21 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"syscall"
|
||||
"unicode/utf16"
|
||||
"unsafe"
|
||||
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
const (
|
||||
mbOK = 0x00000000
|
||||
mbIconError = 0x10
|
||||
mbIconInformation = 0x40
|
||||
mbTaskModal = 0x00002000
|
||||
mbSetForeground = 0x00010000
|
||||
mbTopMost = 0x00040000
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -25,12 +29,79 @@ var (
|
||||
}
|
||||
)
|
||||
|
||||
func showError(title, message string) {
|
||||
if err := messageBox(title, message, mbIconError); err != nil {
|
||||
if zapLogger != nil {
|
||||
zapLogger.Warn("显示错误对话框失败", zap.Error(err))
|
||||
func platformStartupChannels(runner commandRunner) []promptChannel {
|
||||
return []promptChannel{
|
||||
{
|
||||
name: "windows-toast",
|
||||
available: func() error {
|
||||
_, err := findPowerShell(runner)
|
||||
return err
|
||||
},
|
||||
run: func(req promptRequest) error {
|
||||
name, err := findPowerShell(runner)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return runner.Run(promptCommandTimeout, []string{
|
||||
"NEX_TOAST_TITLE=" + req.title,
|
||||
"NEX_TOAST_BODY=" + req.message,
|
||||
}, name, "-NoProfile", "-NonInteractive", "-ExecutionPolicy", "Bypass", "-EncodedCommand", encodePowerShellCommand(windowsToastScript()))
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "windows-messagebox",
|
||||
available: func() error {
|
||||
return messageBoxAvailable()
|
||||
},
|
||||
run: func(req promptRequest) error {
|
||||
return messageBox(req.title, req.message, messageBoxStartupFlags())
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func findPowerShell(runner commandRunner) (string, error) {
|
||||
for _, name := range []string{"powershell.exe", "powershell"} {
|
||||
if _, err := runner.LookPath(name); err == nil {
|
||||
return name, nil
|
||||
}
|
||||
}
|
||||
return "", fmt.Errorf("PowerShell 不可用")
|
||||
}
|
||||
|
||||
func windowsToastScript() string {
|
||||
return `$ErrorActionPreference = 'Stop'
|
||||
Add-Type -AssemblyName System.Runtime.WindowsRuntime
|
||||
$template = [Windows.UI.Notifications.ToastTemplateType]::ToastText02
|
||||
$xml = [Windows.UI.Notifications.ToastNotificationManager]::GetTemplateContent($template)
|
||||
$texts = $xml.GetElementsByTagName('text')
|
||||
$texts.Item(0).AppendChild($xml.CreateTextNode($env:NEX_TOAST_TITLE)) | Out-Null
|
||||
$texts.Item(1).AppendChild($xml.CreateTextNode($env:NEX_TOAST_BODY)) | Out-Null
|
||||
$toast = [Windows.UI.Notifications.ToastNotification]::new($xml)
|
||||
[Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier('Nex').Show($toast)`
|
||||
}
|
||||
|
||||
func encodePowerShellCommand(script string) string {
|
||||
encoded := utf16.Encode([]rune(script))
|
||||
buf := make([]byte, 0, len(encoded)*2)
|
||||
for _, value := range encoded {
|
||||
buf = append(buf, byte(value), byte(value>>8))
|
||||
}
|
||||
return base64.StdEncoding.EncodeToString(buf)
|
||||
}
|
||||
|
||||
func messageBoxAvailable() error {
|
||||
if _, err := syscall.UTF16PtrFromString("Nex"); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := syscall.UTF16PtrFromString("test"); err != nil {
|
||||
return err
|
||||
}
|
||||
return procMessageBoxW.Find()
|
||||
}
|
||||
|
||||
func messageBoxStartupFlags() uint {
|
||||
return mbOK | mbIconError | mbTaskModal | mbSetForeground | mbTopMost
|
||||
}
|
||||
|
||||
func messageBox(title, message string, flags uint) error {
|
||||
|
||||
Reference in New Issue
Block a user