使用Golang制作一个简单的启动Jar包的桌面程序
Posted zhijian233
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用Golang制作一个简单的启动Jar包的桌面程序相关的知识,希望对你有一定的参考价值。
环境:
1、WindowsXP(不支持xp)以上
2、Golang1.11.X及以上
3、JDK or JRE
第三方库:
1、Windows桌面应用库:WALK (https://github.com/lxn/walk)
2、编码转换库:mahonia(https://github.com/axgle/mahonia)
需要实现的功能:
1.点击启动按钮运行Jar包并且将控制台输出到桌面程序的文本框中
2.重复启动应该被禁止
3.点击关闭按钮关闭对应当前启动的Java程序
实现细节(对应上面的功能):
1.开个新线程去执行CMD命令,通过javaw.exe运行Jar包:
// 执行cmd命令 func execCommand(commandName string, params []string) bool cmd := exec.Command(commandName, params...) stdout, err := cmd.StdoutPipe() if err != nil return false cmd.Start() reader := bufio.NewReader(stdout) for out, err2 := reader.ReadBytes(‘\\n‘) if err2 != nil || io.EOF == err2 break // 转换到gbk编码 srcCoder := mahonia.NewDecoder("gbk") resultstr := bytes2str(out) result := srcCoder.ConvertString(resultstr) if pId == 0 // 从输出数据中获取进程id,关闭的时候用的到 pId, _ = strconv.Atoi(GetVeesPid(result, `PID `, " ")) // 输出到文本框 outTE.SetText(outTE.Text() + result) cmd.Wait() return true
启动Jar包:
command := "javaw" params := []string"-Dfile-encoding=UTF-8", "-jar", "vees2.jar", "--server.port=7072" execCommand(command, params)
2.开个线程,定时检测当前启动的Java程序是否仍在运行,是则禁止继续启动
3.关闭程序和开启一样,都调用cmd命令
command := "taskkill" params := []string"/f", "/pid", strconv.Itoa(pId) execCommand(command, params)
这里有一些关于进程的函数:
var ( modKernel32 = syscall.NewLazyDLL("kernel32.dll") procCloseHandle = modKernel32.NewProc("CloseHandle") procCreateToolhelp32Snapshot = modKernel32.NewProc("CreateToolhelp32Snapshot") procProcess32First = modKernel32.NewProc("Process32FirstW") procProcess32Next = modKernel32.NewProc("Process32NextW") procGetCurrentProcessId = modKernel32.NewProc("GetCurrentProcessId") ) // Some constants from the Windows API const ( ERROR_NO_MORE_FILES = 0x12 MAX_PATH = 260 ) // PROCESSENTRY32 is the Windows API structure that contains a process‘s // information. type PROCESSENTRY32 struct Size uint32 CntUsage uint32 ProcessID uint32 DefaultHeapID uintptr ModuleID uint32 CntThreads uint32 ParentProcessID uint32 PriorityClassBase int32 Flags uint32 ExeFile [MAX_PATH]uint16 // Process is an implementation of Process for Windows. type Process struct pid int ppid int exe string // NewWindowsProcess convert external to internal process data structure func NewWindowsProcess(e *PROCESSENTRY32) Process // Find when the string ends for decoding end := 0 for if e.ExeFile[end] == 0 break end++ return Process pid: int(e.ProcessID), ppid: int(e.ParentProcessID), exe: syscall.UTF16ToString(e.ExeFile[:end]), // FindProcess will find process by its ID func FindProcess(pid int) (Process, bool) processes, err := ListProcess() if err == nil for _, process := range processes if process.pid == pid return process, true return Process, false // ListProcess returns list of all active system processes func ListProcess() ([]Process, error) handle, _, _ := procCreateToolhelp32Snapshot.Call(0x00000002, 0) if handle < 0 return nil, syscall.GetLastError() defer procCloseHandle.Call(handle) entry := PROCESSENTRY32 entry.Size = uint32(unsafe.Sizeof(entry)) ret, _, _ := procProcess32First.Call(handle, uintptr(unsafe.Pointer(&entry))) if ret == 0 return nil, fmt.Errorf("Error retrieving process info.") results := make([]Process, 0, 50) for results = append(results, NewWindowsProcess(&entry)) ret, _, _ := procProcess32Next.Call(handle, uintptr(unsafe.Pointer(&entry))) if ret == 0 break return results, nil // MapProcess same as ListProcess but returned as map for lookup by processID func MapProcess() map[int]Process procs, _ := ListProcess() list := make(map[int]Process, len(procs)) for _, proc := range procs list[proc.pid] = proc return list // CurrentProcessID return processID of the process that calls this function func CurrentProcessID() int id, _, _ := procGetCurrentProcessId.Call() return int(id) // IsProcessActive returns true if one of the running processes uses the given executable func IsProcessActive(exe string) bool processes, err := ListProcess() if err == nil for _, process := range processes if process.exe == exe return true return false
窗体的布局:
err := MainWindow Title: "xxx后台服务", AssignTo: &mw, MinSize: Size600, 400, Layout: VBox, MenuItems: []MenuItem Menu Text: "编辑", Items: []MenuItem Separator, Action Text: "复制控制台", OnTriggered: func() if err := walk.Clipboard().SetText(outTE.Text()); err == nil walk.MsgBox(mw, "复制成功", "已复制控制台日志到粘贴板", walk.MsgBoxOK) , , Separator, Action Text: "退出", OnTriggered: func() mw.Close() , , , , Menu Text: "帮助", Items: []MenuItem Separator, Action Text: "如何使用?", OnTriggered: func() walk.MsgBox(mw, "使用", "直接点击‘启动’服务即可,服务端口为访问端口,启动参数可不填", walk.MsgBoxIconQuestion) , , Action Text: "无法启动?", OnTriggered: func() walk.MsgBox(mw, "帮助", "x", walk.MsgBoxIconQuestion) , , Action Text: "版本", OnTriggered: func() walk.MsgBox(mw, "版本", "xxxV1.0\\nby zhiJiaN 2019-09-25", walk.MsgBoxIconQuestion) , , , , , Children: []Widget TextEditAssignTo: &outTE, ReadOnly: true, VScroll: true, Composite Layout: HBox, Children: []Widget Composite Layout: VBox, MaxSize: Size300, 60, MinSize: Size100, 60, Children: []Widget Composite MaxSize: Size50, 60, Layout: VBox Margins: Margins10, 5, 10, 10, , Children: []Widget Composite MaxSize: Size50, 60, Layout: HBox Margins: Margins0, 0, 0, 5, , Children: []Widget Label Text: "服务端口:", , LineEdit AssignTo: &outTEport, MaxLength: 5, Row: 1, MinSize: Size60, 15, OnTextChanged: portChanged, Text: defaultPort, , , , Composite MaxSize: Size50, 60, Layout: HBox Margins: Margins0, 0, 0, 5, , Children: []Widget Label Text: "启动参数:", , LineEdit AssignTo: &outTEext, Row: 1, MinSize: Size160, 15, OnTextChanged: extChanged, , , , , , , , PushButton Text: "启动服务", MinSize: Size80, 60, MaxSize: Size80, 60, AssignTo: &startBtn, OnClicked: func() go startVees() , , PushButton Text: "关闭服务", MinSize: Size80, 60, MaxSize: Size80, 60, AssignTo: &closeBtn, OnClicked: func() stopVees() , , , , , .Create()
效果如下:
结语:刚开始接触Golang,该篇只是学习Golang的简单笔记,需要详细代码请发邮箱,以上代码及实现方式并没有仔细去考究,欢迎读者指正和提问。
以上是关于使用Golang制作一个简单的启动Jar包的桌面程序的主要内容,如果未能解决你的问题,请参考以下文章