147 lines
4.3 KiB
Go
147 lines
4.3 KiB
Go
// run_windows.go
|
|
//go:build windows
|
|
// +build windows
|
|
|
|
package spm
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"golang.org/x/sys/windows/registry"
|
|
)
|
|
|
|
// RegisterApp writes the necessary registry keys, making it appear as officially installed app
|
|
func RegisterApp() error {
|
|
exePath, err := GetInstallDir()
|
|
if err != nil {
|
|
return fmt.Errorf("failed to get install directory: %w", err)
|
|
}
|
|
|
|
// 1. Create Uninstall/Modify entry
|
|
uninstallKeyPath := `Software\Microsoft\Windows\CurrentVersion\Uninstall\SpitfireBrowser`
|
|
uk, _, err := registry.CreateKey(registry.LOCAL_MACHINE, uninstallKeyPath, registry.ALL_ACCESS)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to create uninstall key: %w", err)
|
|
}
|
|
defer uk.Close()
|
|
|
|
if err := uk.SetStringValue("DisplayName", "Spitfire"); err != nil {
|
|
return err
|
|
}
|
|
if err := uk.SetStringValue("UninstallString", exePath+" --uninstall"); err != nil {
|
|
return err
|
|
}
|
|
if err := uk.SetStringValue("ModifyPath", exePath+" --modify"); err != nil {
|
|
return err
|
|
}
|
|
if err := uk.SetStringValue("DisplayIcon", exePath); err != nil {
|
|
return err
|
|
}
|
|
|
|
// 2. Register as a browser for default apps
|
|
clientKeyPath := `Software\Clients\StartMenuInternet\SpitfireBrowser`
|
|
ck, _, err := registry.CreateKey(registry.LOCAL_MACHINE, clientKeyPath, registry.ALL_ACCESS)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to create client key: %w", err)
|
|
}
|
|
defer ck.Close()
|
|
|
|
if err := ck.SetStringValue("", "Spitfire"); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Create Capabilities subkey
|
|
capabilitiesKeyPath := clientKeyPath + `\Capabilities`
|
|
capk, _, err := registry.CreateKey(registry.LOCAL_MACHINE, capabilitiesKeyPath, registry.ALL_ACCESS)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to create capabilities key: %w", err)
|
|
}
|
|
defer capk.Close()
|
|
|
|
if err := capk.SetStringValue("ApplicationName", "Spitfire"); err != nil {
|
|
return err
|
|
}
|
|
if err := capk.SetStringValue("ApplicationDescription", "A custom browser"); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Set file associations
|
|
assocKeyPath := capabilitiesKeyPath + `\FileAssociations`
|
|
ak, _, err := registry.CreateKey(registry.LOCAL_MACHINE, assocKeyPath, registry.ALL_ACCESS)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to create file associations key: %w", err)
|
|
}
|
|
defer ak.Close()
|
|
|
|
associations := map[string]string{
|
|
".html": "SpitfireBrowserHTML",
|
|
"HTTP": "SpitfireBrowserHTML",
|
|
"HTTPS": "SpitfireBrowserHTML",
|
|
}
|
|
for ext, progID := range associations {
|
|
if err := ak.SetStringValue(ext, progID); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// UnregisterApp removes the registry entries created by registerApp.
|
|
func UnregisterApp() error {
|
|
// Remove the Uninstall/Modify entry.
|
|
uninstallKeyPath := `Software\Microsoft\Windows\CurrentVersion\Uninstall\SpitfireBrowser`
|
|
if err := deleteRegistryTree(registry.LOCAL_MACHINE, uninstallKeyPath); err != nil {
|
|
return fmt.Errorf("failed to delete uninstall key: %w", err)
|
|
}
|
|
|
|
// Remove the browser registration entry.
|
|
clientKeyPath := `Software\Clients\StartMenuInternet\SpitfireBrowser`
|
|
if err := deleteRegistryTree(registry.LOCAL_MACHINE, clientKeyPath); err != nil {
|
|
return fmt.Errorf("failed to delete client key: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// deleteRegistryTree recursively deletes a registry key and all its subkeys.
|
|
func deleteRegistryTree(root registry.Key, path string) error {
|
|
// Open the key with ALL_ACCESS permissions.
|
|
key, err := registry.OpenKey(root, path, registry.ALL_ACCESS)
|
|
if err != nil {
|
|
// If the key does not exist, there's nothing to do.
|
|
if err == registry.ErrNotExist {
|
|
return nil
|
|
}
|
|
return err
|
|
}
|
|
// Read the names of all subkeys.
|
|
subKeys, err := key.ReadSubKeyNames(-1)
|
|
key.Close() // Close the key so it can be deleted later.
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Recursively delete each subkey.
|
|
for _, subKey := range subKeys {
|
|
subKeyPath := path + `\` + subKey
|
|
if err := deleteRegistryTree(root, subKeyPath); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
// Finally, delete the (now empty) key.
|
|
return registry.DeleteKey(root, path)
|
|
}
|
|
|
|
// IsRegistered returns true if the application is registered (installed) in the registry.
|
|
func IsRegistered() bool {
|
|
// Try to open the uninstall key with read-only access.
|
|
key, err := registry.OpenKey(registry.LOCAL_MACHINE, `Software\Microsoft\Windows\CurrentVersion\Uninstall\SpitfireBrowser`, registry.READ)
|
|
if err != nil {
|
|
// If the key cannot be opened, assume the app is not registered.
|
|
return false
|
|
}
|
|
defer key.Close()
|
|
return true
|
|
}
|