diff --git a/golang_learn/data_func/go_to_windows/Main.go b/golang_learn/data_func/go_to_service/main.go similarity index 100% rename from golang_learn/data_func/go_to_windows/Main.go rename to golang_learn/data_func/go_to_service/main.go diff --git a/golang_learn/data_func/go_to_windows/build.bat b/golang_learn/data_func/go_to_windows/build.bat new file mode 100644 index 0000000..cfe8b15 --- /dev/null +++ b/golang_learn/data_func/go_to_windows/build.bat @@ -0,0 +1,5 @@ +set GO111MODULE=on +set GOARCH=386 +rsrc -manifest main.manifest -ico serviceMonitor.ico -o rsrc.syso +go build -ldflags="-s -w -H=windowsgui" +upx -9 ./serviceMonitor.exe diff --git a/golang_learn/data_func/go_to_windows/main.go b/golang_learn/data_func/go_to_windows/main.go new file mode 100644 index 0000000..d4d96a0 --- /dev/null +++ b/golang_learn/data_func/go_to_windows/main.go @@ -0,0 +1,265 @@ +// +build windows +// +build 386 +package main + +import ( + "fmt" + "github.com/lxn/walk" + . "github.com/lxn/walk/declarative" + "github.com/lxn/win" + "golang.org/x/sys/windows" + "os/exec" + "syscall" + "time" +) + +type myApp struct { + title string + msg *walk.TextEdit + mw *walk.MainWindow +} + +type myService struct { + text string + serviceName string + labelState *walk.Label + btnStart *walk.PushButton + btnStop *walk.PushButton +} + +var app myApp +var service1, service2, service3 myService + +func init() { + app.title = "XXXX管理系统-运行监控" + service1 = myService{ + text: "MySql51(MySql数据库)", + serviceName: "MySql51", + } + service2 = myService{ + text: "Web服务(nginx)", + serviceName: "nginx", + } + service3 = myService{ + text: "XXXX系统", + serviceName: "xxxx-server", + } +} + +func main() { + _ = getWindows() + + walk.App().SetProductName(app.title) + walk.App().SetOrganizationName("dwt") + + _ = service1.labelState.SetText("未安装") + _ = service2.labelState.SetText("未安装") + _ = service3.labelState.SetText("未安装") + service1.btnStart.Clicked().Attach(func() { + startService(service1) + }) + service1.btnStop.Clicked().Attach(func() { + stopService(service1) + }) + service2.btnStart.Clicked().Attach(func() { + startService(service2) + }) + service2.btnStop.Clicked().Attach(func() { + stopService(service2) + }) + service3.btnStart.Clicked().Attach(func() { + startService(service3) + }) + service3.btnStop.Clicked().Attach(func() { + stopService(service3) + }) + + go flushServiceStat(service1) + go flushServiceStat(service2) + go flushServiceStat(service3) + + app.mw.Show() + app.mw.Run() +} + +func setServiceState(service myService, msg string, btnStartStatus bool, btnStopStatus bool) { + _ = service.labelState.SetText(msg) + service.btnStart.SetEnabled(btnStartStatus) + service.btnStop.SetEnabled(btnStopStatus) +} + +// 刷新服务状态的协程程序 +func flushServiceStat(service myService) { + for { + winService, err := NewWinService(service.serviceName) + if winService == nil || err != nil { + if err == windows.ERROR_SERVICE_DOES_NOT_EXIST { + setServiceState(service, "未安装", false, false) + } else { + setServiceState(service, "服务打开失败", false, false) + } + } else { + if winService.IsStop() { + setServiceState(service, "已经停止", true, false) + } else if winService.IsRunning() { + setServiceState(service, "正在运行", false, true) + } + } + time.Sleep(time.Second) + } +} + +// 启动服务 +func startService(service myService) { + s, err := NewWinService(service.serviceName) + if s == nil || err != nil { + return + } + showMsg(service.serviceName + " 服务开始启动......") + err = s.StartService() + if err != nil { + showMsg(service.serviceName + " 服务启动失败!") + } else { + showMsg(service.serviceName + " 服务启动成功。") + } +} + +// 停止服务 +func stopService(service myService) { + s, err := NewWinService(service.serviceName) + if s == nil || err != nil { + return + } + showMsg(service.serviceName + " 服务开始停止......") + err = s.StopService() + if err != nil { + showMsg(service.serviceName + " 服务停止失败!") + } else { + showMsg(service.serviceName + " 服务停止成功。") + } +} + +func showMsg(msg string) { + app.msg.AppendText(time.Now().Format("2006-01-02 15:04:05 ")) + app.msg.AppendText(msg) + app.msg.AppendText("\r\n") +} + +// 初始始化窗体 +func getWindows() error { + icon, _ := walk.NewIconFromResourceId(3) + err := MainWindow{ + Visible: false, + AssignTo: &app.mw, + Title: app.title, + Size: Size{500, 360}, + Font: Font{Family: "微软雅黑", PointSize: 9}, + Icon: icon, + Layout: VBox{}, + Children: []Widget{ + GroupBox{ + Title: "基础服务状态", + Layout: Grid{Columns: 3}, + Children: []Widget{ + Label{Text: service1.text, MinSize: Size{220, 30}, TextColor: walk.RGB(255, 255, 0)}, + Label{AssignTo: &service1.labelState, Text: "正在运行", MinSize: Size{80, 30}}, + Composite{ + Layout: HBox{}, + MaxSize: Size{132, 30}, + Children: []Widget{ + PushButton{ + AssignTo: &service1.btnStop, + MaxSize: Size{60, 30}, + Text: "停止", + }, + PushButton{ + AssignTo: &service1.btnStart, + MaxSize: Size{60, 30}, + Text: "启动", + }, + }, + }, + Label{Text: service2.text}, + Label{AssignTo: &service2.labelState, Text: "正在运行"}, + Composite{ + Layout: HBox{}, + MaxSize: Size{132, 30}, + Children: []Widget{ + PushButton{ + AssignTo: &service2.btnStop, + MaxSize: Size{60, 30}, + Text: "停止", + }, + PushButton{ + AssignTo: &service2.btnStart, + MaxSize: Size{60, 30}, + Text: "启动", + }, + }, + }, + }, + }, + GroupBox{ + Title: "业务服务状态", + Layout: Grid{Columns: 3}, + Children: []Widget{ + Label{Text: service3.text, MinSize: Size{220, 30}}, + Label{AssignTo: &service3.labelState, Text: "正在运行", MinSize: Size{80, 30}}, + Composite{ + Layout: HBox{}, + MaxSize: Size{132, 30}, + Children: []Widget{ + PushButton{ + AssignTo: &service3.btnStop, + MaxSize: Size{60, 30}, + Text: "停止", + }, + PushButton{ + AssignTo: &service3.btnStart, + MaxSize: Size{60, 30}, + Text: "启动", + }, + }, + }, + }, + }, + TextEdit{AssignTo: &app.msg, VScroll: true, ReadOnly: true}, + Composite{ + Layout: HBox{}, + Children: []Widget{ + PushButton{ + MinSize: Size{160, 30}, + Text: "打开windows服务管理程序", + OnClicked: func() { + c := exec.Command("cmd", "/C", "SERVICES.MSC") + c.SysProcAttr = &syscall.SysProcAttr{HideWindow: true} // 不显示命令窗口 + if err := c.Start(); err != nil { + showMsg(fmt.Sprintf("打开windows服务管理程序失败, 错误信息: %s", err)) + } + }, + }, + HSpacer{}, + PushButton{ + MinSize: Size{121, 30}, + Text: "关闭本监控窗口", + OnClicked: func() { + walk.App().Exit(0) + }, + }, + }, + }, + }, + OnSizeChanged: func() { + _ = app.mw.SetSize(walk.Size(Size{500, 360})) + }, + }.Create() + winLong := win.GetWindowLong(app.mw.Handle(), win.GWL_STYLE) + // 不能调整窗口大小,禁用最大化按钮 + win.SetWindowLong(app.mw.Handle(), win.GWL_STYLE, winLong & ^win.WS_SIZEBOX & ^win.WS_MAXIMIZEBOX & ^win.WS_SIZEBOX) + // 设置窗体生成在屏幕的正中间,并处理高分屏的情况 + // 窗体横坐标 = ( 屏幕宽度 - 窗体宽度 ) / 2 + // 窗体纵坐标 = ( 屏幕高度 - 窗体高度 ) / 2 + _ = app.mw.SetX((int(win.GetSystemMetrics(0)) - app.mw.Width()) / 2 / app.mw.DPI() * 96) + _ = app.mw.SetY((int(win.GetSystemMetrics(1)) - app.mw.Height()) / 2 / app.mw.DPI() * 96) + return err +} diff --git a/golang_learn/data_func/go_to_windows/main.manifest b/golang_learn/data_func/go_to_windows/main.manifest new file mode 100644 index 0000000..4a042b0 --- /dev/null +++ b/golang_learn/data_func/go_to_windows/main.manifest @@ -0,0 +1,22 @@ + + + + + + + + + + + PerMonitorV2, PerMonitor + True + + + + + + + + + + \ No newline at end of file diff --git a/golang_learn/data_func/go_to_windows/rsrc.syso b/golang_learn/data_func/go_to_windows/rsrc.syso new file mode 100644 index 0000000..c5b0a40 Binary files /dev/null and b/golang_learn/data_func/go_to_windows/rsrc.syso differ diff --git a/golang_learn/data_func/go_to_windows/serviceMonitor.ico b/golang_learn/data_func/go_to_windows/serviceMonitor.ico new file mode 100644 index 0000000..0cf91e5 Binary files /dev/null and b/golang_learn/data_func/go_to_windows/serviceMonitor.ico differ diff --git a/golang_learn/data_func/go_to_windows/winService.go b/golang_learn/data_func/go_to_windows/winService.go new file mode 100644 index 0000000..c126f39 --- /dev/null +++ b/golang_learn/data_func/go_to_windows/winService.go @@ -0,0 +1,139 @@ +package main + +import ( + "fmt" + "github.com/shirou/gopsutil/winservices" + "golang.org/x/sys/windows/svc" + "golang.org/x/sys/windows/svc/mgr" + "time" +) + +// 定义Service对象 +type Service struct { + Name string + srv *winservices.Service + Config mgr.Config + Status winservices.ServiceStatus +} + +// 得到Service信息 +func (s *Service) getServiceDetail() error { + defer func() { + if err := recover(); err != nil { + return + } + }() + err := s.srv.GetServiceDetail() + if err != nil { + // 服务打开失败 + return err + } + s.Name = s.srv.Name + s.Status = s.srv.Status + s.Config = s.srv.Config + return nil +} + +// 启动一个服务 +func (s *Service) StartService() error { + return StartService(s.Name) +} + +// 停止一个服务 +func (s *Service) StopService() error { + return StopService(s.Name) +} + +// 服务是否已经停止 +func (s *Service) IsStop() bool { + return s.Status.State == svc.Stopped +} + +// 服务是否正在运行 +func (s *Service) IsRunning() bool { + return s.Status.State == svc.Running +} + +// 新建一个Service对象 +func NewWinService(serviceName string) (*Service, error) { + winService, err := winservices.NewService(serviceName) + if err != nil { + return nil, err + } + result := &Service{ + Name: serviceName, + srv: winService, + } + err = result.getServiceDetail() + return result, err +} + +// 得到Service信息 +func GetServiceInfo(serviceName string) (*winservices.Service, error) { + defer func() { + if err := recover(); err != nil { + return + } + }() + newservice, _ := winservices.NewService(serviceName) + err := newservice.GetServiceDetail() + if err != nil { + fmt.Println(serviceName, "服务打开失败!") + return nil, err + } + return newservice, nil +} + +// 启动一个服务 +func StartService(name string) error { + m, err := mgr.Connect() + if err != nil { + return err + } + defer m.Disconnect() + s, err := m.OpenService(name) + if err != nil { + return fmt.Errorf("could not access service: %v", err) + } + defer s.Close() + err = s.Start("is", "manual-started") + if err != nil { + return fmt.Errorf("could not start service: %v", err) + } + return nil +} + +// 停止一个服务 +func StopService(name string) error { + return ControlService(name, svc.Stop, svc.Stopped) +} + +// 改一个服务状态, +func ControlService(name string, c svc.Cmd, to svc.State) error { + m, err := mgr.Connect() + if err != nil { + return err + } + defer m.Disconnect() + s, err := m.OpenService(name) + if err != nil { + return fmt.Errorf("could not access service: %v", err) + } + defer s.Close() + status, err := s.Control(c) + if err != nil { + return fmt.Errorf("could not send control=%d: %v", c, err) + } + timeout := time.Now().Add(10 * time.Second) + for status.State != to { + if timeout.Before(time.Now()) { + return fmt.Errorf("timeout waiting for service to go to state=%d", to) + } + time.Sleep(300 * time.Millisecond) + status, err = s.Query() + if err != nil { + return fmt.Errorf("could not retrieve service status: %v", err) + } + } + return nil +} diff --git a/golang_learn/go.mod b/golang_learn/go.mod index 8aa8511..3747913 100644 --- a/golang_learn/go.mod +++ b/golang_learn/go.mod @@ -23,6 +23,7 @@ require ( github.com/mattn/go-oci8 v0.1.1 github.com/mattn/go-sqlite3 v1.14.8 github.com/russross/blackfriday v1.6.0 + github.com/shirou/gopsutil v2.20.4+incompatible github.com/spf13/viper v1.8.1 github.com/yeka/zip v0.0.0-20180914125537-d046722c6feb golang.org/x/exp/errors v0.0.0-20210715201039-d37aa40e8013 diff --git a/golang_learn/go.sum b/golang_learn/go.sum index 0fcbda2..87e3a4d 100644 --- a/golang_learn/go.sum +++ b/golang_learn/go.sum @@ -266,6 +266,8 @@ github.com/russross/blackfriday v1.6.0 h1:KqfZb0pUVN2lYqZUYRddxF4OR8ZMURnJIG5Y3V github.com/russross/blackfriday v1.6.0/go.mod h1:ti0ldHuxg49ri4ksnFxlkCfN+hvslNlmVHqNRXXJNAY= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/shirou/gopsutil v2.20.4+incompatible h1:cMT4rxS55zx9NVUnCkrmXCsEB/RNfG9SwHY9evtX8Ng= +github.com/shirou/gopsutil v2.20.4+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=