//go:build windows package remote import ( "fmt" "os" "github.com/KarpelesLab/vncpasswd" "github.com/kardianos/service" "golang.org/x/sys/windows/registry" ) var VncService service.Service // ReadVncServerConfig 从注册表读取 TightVNC 服务端配置(键值缺失按零值返回) func ReadVncServerConfig() (VncServerConfig, error) { var config VncServerConfig key, err := registry.OpenKey(registry.LOCAL_MACHINE, "SOFTWARE\\TightVNC\\Server", registry.ALL_ACCESS) if err != nil { return config, err } defer key.Close() config.ExtraPorts, _, _ = key.GetStringValue("ExtraPorts") config.QueryTimeout, _, _ = GetDwordValue(key, "QueryTimeout") config.QueryAcceptOnTimeout, _, _ = GetDwordValue(key, "QueryAcceptOnTimeout") config.LocalInputPriorityTimeout, _, _ = GetDwordValue(key, "LocalInputPriorityTimeout") config.LocalInputPriority, _, _ = GetDwordValue(key, "LocalInputPriority") config.BlockRemoteInput, _, _ = GetDwordValue(key, "BlockRemoteInput") config.BlockLocalInput, _, _ = GetDwordValue(key, "BlockLocalInput") config.IpAccessControl, _, _ = key.GetStringValue("IpAccessControl") config.RfbPort, _, _ = GetDwordValue(key, "RfbPort") config.HttpPort, _, _ = GetDwordValue(key, "HttpPort") config.DisconnectAction, _, _ = GetDwordValue(key, "DisconnectAction") config.AcceptRfbConnections, _, _ = GetDwordValue(key, "AcceptRfbConnections") config.UseVncAuthentication, _, _ = GetDwordValue(key, "UseVncAuthentication") config.UseControlAuthentication, _, _ = GetDwordValue(key, "UseControlAuthentication") config.RepeatControlAuthentication, _, _ = GetDwordValue(key, "RepeatControlAuthentication") config.LoopbackOnly, _, _ = GetDwordValue(key, "LoopbackOnly") config.AcceptHttpConnections, _, _ = GetDwordValue(key, "AcceptHttpConnections") config.EnableFileTransfers, _, _ = GetDwordValue(key, "EnableFileTransfers") config.RemoveWallpaper, _, _ = GetDwordValue(key, "RemoveWallpaper") config.UseD3D, _, _ = GetDwordValue(key, "UseD3D") config.UseMirrorDriver, _, _ = GetDwordValue(key, "UseMirrorDriver") config.EnableUrlParams, _, _ = GetDwordValue(key, "EnableUrlParams") config.Password, _, _ = key.GetBinaryValue("Password") config.AlwaysShared, _, _ = GetDwordValue(key, "AlwaysShared") config.NeverShared, _, _ = GetDwordValue(key, "NeverShared") config.DisconnectClients, _, _ = GetDwordValue(key, "DisconnectClients") config.PollingInterval, _, _ = GetDwordValue(key, "PollingInterval") config.AllowLoopback, _, _ = GetDwordValue(key, "AllowLoopback") config.VideoRecognitionInterval, _, _ = GetDwordValue(key, "VideoRecognitionInterval") config.GrabTransparentWindows, _, _ = GetDwordValue(key, "GrabTransparentWindows") config.SaveLogToAllUsersPath, _, _ = GetDwordValue(key, "SaveLogToAllUsersPath") config.RunControlInterface, _, _ = GetDwordValue(key, "RunControlInterface") config.IdleTimeout, _, _ = GetDwordValue(key, "IdleTimeout") config.VideoClasses, _, _ = key.GetStringValue("VideoClasses") config.VideoRects, _, _ = key.GetStringValue("VideoRects") config.ConnectToRdp, _, _ = GetDwordValue(key, "ConnectToRdp") return config, nil } // GetDwordValue 读取 REG_DWORD 类型注册表值 func GetDwordValue(k registry.Key, name string) (val uint32, valtype uint32, err error) { val64 := uint64(0) val64, valtype, err = k.GetIntegerValue(name) val = uint32(val64) return } var vncSvcConfig = &service.Config{ Name: "tvnserver", DisplayName: "TightVNC Server", Description: "TightVNC Server (managed by remote-core)", Arguments: []string{"-service"}, } // InstallVncServer 绿色安装 TightVNC 服务端(需管理员权限)。 // 最新版注册表全集配置(VncClientDefaultConfig 37 项, 随机 8 位密码)→ 注册系统服务。 // 装而不启:服务注册后保持 Stopped, 等远程指令再 VncStart(避免常驻监听开端口); // 若服务已在运行则重启以加载新配置。返回生成的明文密码(调用方自行上报/展示)。 func InstallVncServer(exePath string) (string, error) { if finfo, err := os.Stat(exePath); err != nil || finfo.IsDir() { return "", fmt.Errorf("tvnserver.exe 不存在: %s", exePath) } // 最新版 TightVNC 注册表配置全集(含随机密码) config := VncClientDefaultConfig(true) if err := WriteVncServerConfig(config); err != nil { return "", err } // 注册系统服务:未安装→安装; 运行中→重启加载新配置; 已停止→保持 vncSvcConfig.Executable = exePath if err := VncInit(); err != nil { return "", err } status, err := VncService.Status() switch { case err != nil: // 未安装(kardianos 对未安装服务 Status 返回错误) if err := VncInstall(); err != nil { return "", err } case status == service.StatusRunning: if err := VncRestart(); err != nil { return "", err } } return VncPasswordDecrypt(config.Password), nil } // VncInit 初始化 VNC 服务对象,VncInstall/VncStart 等操作前必须调用 func VncInit() error { var err error VncService, err = service.New(nil, vncSvcConfig) if err != nil { return err } return nil } // VncInstall 安装 TightVNC 服务 func VncInstall() error { err := VncService.Install() if err != nil { return err } return nil } // VncUninstall 停止并卸载 TightVNC 服务 func VncUninstall() error { _ = VncService.Stop() err := VncService.Uninstall() if err != nil { return err } return nil } // VncStart 启动 TightVNC 服务 func VncStart() error { err := VncService.Start() if err != nil { return err } return nil } // VncStop 停止 TightVNC 服务 func VncStop() error { err := VncService.Stop() if err != nil { return err } return nil } // VncRestart 重启 TightVNC 服务 func VncRestart() error { err := VncService.Stop() if err != nil { return err } err = VncService.Start() if err != nil { return err } return nil } // VncPasswordCrypt 加密 VNC 密码(TightVNC 注册表存储格式) func VncPasswordCrypt(password string) []byte { return vncpasswd.Crypt(password) } // VncPasswordDecrypt 解密 VNC 密码 func VncPasswordDecrypt(data []byte) string { return vncpasswd.Decrypt(data) }