//go:build windows package main import ( "errors" "fmt" "os" "os/exec" "path/filepath" "syscall" "unsafe" ) var ( shell32 = syscall.NewLazyDLL("shell32.dll") shellExecuteExW = shell32.NewProc("ShellExecuteExW") ) const ( seeMaskNocloseprocess = 0x00000040 ) type shellExecuteInfo struct { cbSize uint32 fMask uint32 hwnd uintptr lpVerb *uint16 lpFile *uint16 lpParameters *uint16 lpDirectory *uint16 nShow int32 hInstApp uintptr lpIDList uintptr lpClass *uint16 hkeyClass uintptr dwHotKey uint32 hIcon uintptr hProcess uintptr } func getInstallDir() (string, error) { programFiles := os.Getenv("ProgramFiles") if programFiles == "" { return "", errors.New("ProgramFiles ist nicht gesetzt") } return filepath.Join(programFiles, "logofclient"), nil } func platformRunPrivileged(config Config, action string) error { if isWindowsAdmin() { return runAction(config, action) } return runElevated(action) } func isWindowsAdmin() bool { // Ein einfacher und robuster Test: // Versuch, in das Windows-Systemverzeichnis zu schreiben. // // Da wir dort natürlich nichts verändern wollen, verwenden wir // stattdessen "net session". Der Befehl funktioniert nur mit // Administratorrechten. cmd := exec.Command("net", "session") cmd.Stdout = nil cmd.Stderr = nil return cmd.Run() == nil } func runElevated(action string) error { exe, err := os.Executable() if err != nil { return fmt.Errorf("Pfad des Installers konnte nicht ermittelt werden: %w", err) } verb, err := syscall.UTF16PtrFromString("runas") if err != nil { return err } file, err := syscall.UTF16PtrFromString(exe) if err != nil { return err } parameters, err := syscall.UTF16PtrFromString(action) if err != nil { return err } info := shellExecuteInfo{ cbSize: uint32(unsafe.Sizeof(shellExecuteInfo{})), fMask: seeMaskNocloseprocess, lpVerb: verb, lpFile: file, lpParameters: parameters, nShow: 1, // SW_SHOWNORMAL } ret, _, callErr := shellExecuteExW.Call(uintptr(unsafe.Pointer(&info))) if ret == 0 { // ERROR_CANCELLED = 1223: // Benutzer hat den UAC-Dialog abgebrochen. if errno, ok := callErr.(syscall.Errno); ok && errno == 1223 { fmt.Println("Administratorrechte wurden nicht erteilt.") return nil } return fmt.Errorf("Administratorrechte konnten nicht angefordert werden: %w", callErr) } // Auf die erhöhte Instanz warten. if info.hProcess != 0 { handle := syscall.Handle(info.hProcess) defer syscall.CloseHandle(handle) _, err := syscall.WaitForSingleObject(handle, syscall.INFINITE) if err != nil { return fmt.Errorf("auf erhöhte Instanz konnte nicht gewartet werden: %w", err) } } return nil }