feat(autostart): enhance autostart configuration handling on windows. fix #4231

* Improved logging for autostart setting mismatches.
* Added functionality to attempt fixing autostart configuration when mismatches are detected.
* Updated registry access methods for better clarity and error handling.
* Introduced `setStartupApproved` and `removeStartupApproved` functions to manage startup approval status in Windows Settings.
This commit is contained in:
qianlifeng 2025-07-13 18:48:52 +08:00
parent 7793308f27
commit 8c74c5cb63
2 changed files with 150 additions and 14 deletions

View File

@ -64,8 +64,25 @@ func (m *Manager) Init(ctx context.Context) error {
} else {
configAutostart := m.woxSetting.EnableAutostart.Get()
if actualAutostart != configAutostart {
util.GetLogger().Warn(ctx, fmt.Sprintf("Autostart setting mismatch: config %v, actual %v. Updating config.", configAutostart, actualAutostart))
m.woxSetting.EnableAutostart.Set(actualAutostart)
util.GetLogger().Warn(ctx, fmt.Sprintf("Autostart setting mismatch: config %v, actual %v", configAutostart, actualAutostart))
// If config says autostart should be enabled but actual is false,
// try to re-enable autostart (this will fix broken autostart entries)
if configAutostart && !actualAutostart {
util.GetLogger().Info(ctx, "Attempting to fix autostart configuration...")
fixErr := autostart.SetAutostart(ctx, true)
if fixErr != nil {
util.GetLogger().Error(ctx, fmt.Sprintf("Failed to fix autostart: %s", fixErr.Error()))
// Update config to match actual state
m.woxSetting.EnableAutostart.Set(false)
} else {
util.GetLogger().Info(ctx, "Autostart configuration fixed successfully")
}
} else {
// Update config to match actual state
m.woxSetting.EnableAutostart.Set(actualAutostart)
}
err := m.SaveWoxSetting(ctx)
if err != nil {
util.GetLogger().Error(ctx, fmt.Sprintf("Failed to save updated autostart setting: %s", err.Error()))

View File

@ -8,15 +8,16 @@ import (
)
func setAutostart(enable bool) error {
key, _, err := registry.CreateKey(
// Set the main Run registry entry
runKey, _, err := registry.CreateKey(
registry.CURRENT_USER,
`Software\Microsoft\Windows\CurrentVersion\Run`,
registry.ALL_ACCESS,
)
if err != nil {
return fmt.Errorf("failed to access registry: %w", err)
return fmt.Errorf("failed to access Run registry: %w", err)
}
defer key.Close()
defer runKey.Close()
valueName := "WoxLauncher"
@ -25,14 +26,36 @@ func setAutostart(enable bool) error {
if err != nil {
return fmt.Errorf("failed to get executable path: %w", err)
}
err = key.SetStringValue(valueName, exePath)
err = runKey.SetStringValue(valueName, exePath)
if err != nil {
return fmt.Errorf("failed to set registry value: %w", err)
return fmt.Errorf("failed to set Run registry value: %w", err)
}
// Verify the value was set correctly
verifyValue, _, verifyErr := runKey.GetStringValue(valueName)
if verifyErr != nil {
return fmt.Errorf("failed to verify Run registry value: %w", verifyErr)
}
if verifyValue != exePath {
return fmt.Errorf("Run registry value verification failed: expected %s, got %s", exePath, verifyValue)
}
// Set the StartupApproved entry to enable the startup app in Windows Settings
err = setStartupApproved(valueName, true)
if err != nil {
return fmt.Errorf("failed to set StartupApproved: %w", err)
}
} else {
err = key.DeleteValue(valueName)
err = runKey.DeleteValue(valueName)
if err != nil && err != registry.ErrNotExist {
return fmt.Errorf("failed to delete registry value: %w", err)
return fmt.Errorf("failed to delete Run registry value: %w", err)
}
// Remove the StartupApproved entry
err = removeStartupApproved(valueName)
if err != nil {
return fmt.Errorf("failed to remove StartupApproved: %w", err)
}
}
@ -40,24 +63,120 @@ func setAutostart(enable bool) error {
}
func isAutostart() (bool, error) {
key, _, err := registry.CreateKey(
runKey, _, err := registry.CreateKey(
registry.CURRENT_USER,
`Software\Microsoft\Windows\CurrentVersion\Run`,
registry.QUERY_VALUE,
)
if err != nil {
return false, fmt.Errorf("failed to access registry: %w", err)
return false, fmt.Errorf("failed to access Run registry: %w", err)
}
defer key.Close()
defer runKey.Close()
valueName := "WoxLauncher"
_, _, err = key.GetStringValue(valueName)
value, _, err := runKey.GetStringValue(valueName)
if err == registry.ErrNotExist {
return false, nil
}
if err != nil {
return false, fmt.Errorf("failed to get registry value: %w", err)
return false, fmt.Errorf("failed to get Run registry value: %w", err)
}
// Check if the executable path still exists
if _, statErr := os.Stat(value); os.IsNotExist(statErr) {
// The registered executable doesn't exist, this means autostart is broken
// We should return false so the system can detect and fix this
return false, nil
}
// Check StartupApproved status - if it exists and is disabled, return false
approved, err := isStartupApproved(valueName)
if err != nil {
// If we can't read StartupApproved, assume it's enabled (backward compatibility)
return true, nil
}
return approved, nil
}
// setStartupApproved sets the StartupApproved registry entry to enable/disable startup app in Windows Settings
func setStartupApproved(valueName string, enabled bool) error {
approvedKey, _, err := registry.CreateKey(
registry.CURRENT_USER,
`Software\Microsoft\Windows\CurrentVersion\Explorer\StartupApproved\Run`,
registry.ALL_ACCESS,
)
if err != nil {
return fmt.Errorf("failed to access StartupApproved registry: %w", err)
}
defer approvedKey.Close()
// The StartupApproved value is a binary value
// Enabled: starts with 0x02 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
// Disabled: starts with 0x03 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
var binaryValue []byte
if enabled {
// Enabled state - first byte is 0x02
binaryValue = []byte{0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
} else {
// Disabled state - first byte is 0x03
binaryValue = []byte{0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
}
err = approvedKey.SetBinaryValue(valueName, binaryValue)
if err != nil {
return fmt.Errorf("failed to set StartupApproved binary value: %w", err)
}
return nil
}
// removeStartupApproved removes the StartupApproved registry entry
func removeStartupApproved(valueName string) error {
approvedKey, _, err := registry.CreateKey(
registry.CURRENT_USER,
`Software\Microsoft\Windows\CurrentVersion\Explorer\StartupApproved\Run`,
registry.ALL_ACCESS,
)
if err != nil {
return fmt.Errorf("failed to access StartupApproved registry: %w", err)
}
defer approvedKey.Close()
err = approvedKey.DeleteValue(valueName)
if err != nil && err != registry.ErrNotExist {
return fmt.Errorf("failed to delete StartupApproved value: %w", err)
}
return nil
}
// isStartupApproved checks if the startup app is approved (enabled) in Windows Settings
func isStartupApproved(valueName string) (bool, error) {
approvedKey, _, err := registry.CreateKey(
registry.CURRENT_USER,
`Software\Microsoft\Windows\CurrentVersion\Explorer\StartupApproved\Run`,
registry.QUERY_VALUE,
)
if err != nil {
return false, fmt.Errorf("failed to access StartupApproved registry: %w", err)
}
defer approvedKey.Close()
binaryValue, _, err := approvedKey.GetBinaryValue(valueName)
if err == registry.ErrNotExist {
// If StartupApproved entry doesn't exist, assume it's enabled
return true, nil
}
if err != nil {
return false, fmt.Errorf("failed to get StartupApproved binary value: %w", err)
}
// Check the first byte: 0x02 = enabled, 0x03 = disabled
if len(binaryValue) > 0 {
return binaryValue[0] == 0x02, nil
}
// If binary value is empty, assume enabled
return true, nil
}