0%

vbs 启动进程并记录 PID

Windows下,有时候需要管理一些程序,在 unix 系列下的时候都是使用 shell 脚本,但在 Windows 下却没有 shell 的默认支持,所以我编写了简单的 startup.vbs 以及 shutdown.vbs 脚本,给予有需要的人以及未来的我进行照抄借鉴。

启动脚本

启动脚本做了三件事情,检查 pid.txt 文件是否存在,如果存在,则杀死 pid.txt 里面的 PID 进程;然后执行 command=启动命令 ,并且将 PID 记录到 pid.txt ,方便下次启动的时候kill

startup.vbs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
' If running under wscript.exe, relaunch under cscript.exe in a hidden window...
' 如果当前进程为 wscript ,则替换为 隐藏的 cscript 运行
If InStr(1, WScript.FullName, "wscript.exe", vbTextCompare) > 0 Then
With CreateObject("WScript.Shell")
WScript.Quit .Run("cscript.exe """ & WScript.ScriptFullName & """", 0, True)
End With
End If

' 定义 wscript 对象
dim objShell
dim command
dim last_pid
set objShell=wscript.createObject("wscript.shell")
'vbs代码开始----------------------------------------------

function get_last_pid()
Dim Fso ,tf,fileName,strLine
strLine=Empty
fileName=getfolder() & "\pid.txt"
Set Fso = CreateObject("Scripting.FileSystemObject")
If Fso.fileexists(fileName)Then
'read from file
Set tf =Fso.opentextfile(fileName,1)
Do While tf.atendofstream<>True
strLine = tf.ReadLine
Loop
tf.close
End If
Set Fso = Nothing
get_last_pid=strLine
end function

function set_last_pid(pid)
Dim fso ,fw,fileName
fileName=getfolder() & "\pid.txt"
set fso=CreateObject("scripting.filesystemobject")
set fw=fso.opentextfile(fileName,2,true)
fw.writeline pid
fw.close
Set fso = Nothing
end function

sub kill_pid(pid)
' 发送强制结束信号
wscript.createObject("wscript.shell").Run "taskkill /F /PID " & pid , 0 , true
end sub

' 获取当前文件夹
function getfolder()
getfolder=left(wscript.scriptfullname,instrrev(wscript.scriptfullname,"\")-1)
end function

' 设置运行目录为当前目录
objShell.CurrentDirectory = getfolder()

last_pid=get_last_pid()
if IsEmpty(last_pid) Then
else
' 杀掉进程
kill_pid last_pid
' 等待 300 ms 避免程序文件占用
WScript.Sleep(300)
' 删除 pid.txt 文件
CreateObject("Scripting.FileSystemObject").DeleteFile(getfolder() & "\pid.txt"), True
end if

' 设置启动命令
command=启动命令
' 举个例子
' command=getfolder() & "\..\openjdk\bin\java.exe -Dfile.encoding=utf-8 -cp " & chr(34) & getfolder() & "\lib\*;" & getfolder() & "\libx\*;" & getfolder() & "\config " & chr(34) & " com.kekxv.bootstrap.ApplicationMain"

set iReturn=objShell.Exec(command)
' WshExec类具有属性ExitCode,ProcessID,Status,StdErr,StdIn,StdOut以及一个函数Terminate,这些属性和函数都很好理解。
' 程序 PID
Wscript.Echo "PID : " & iReturn.ProcessID
set_last_pid iReturn.ProcessID

结束脚本

结束脚本只做了两件事情,检查 pid.txt 文件是否存在,如果存在,则杀死 pid.txt 里面的 PID 进程;删除 pid.txt 文件。

shutdown.vbs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
' If running under wscript.exe, relaunch under cscript.exe in a hidden window...
' 如果当前进程为 wscript ,则替换为 隐藏的 cscript 运行
If InStr(1, WScript.FullName, "wscript.exe", vbTextCompare) > 0 Then
With CreateObject("WScript.Shell")
WScript.Quit .Run("cscript.exe """ & WScript.ScriptFullName & """", 0, True)
End With
End If

' 定义 wscript 对象
dim objShell
dim command
dim last_pid
set objShell=wscript.createObject("wscript.shell")
'vbs代码开始----------------------------------------------

function get_last_pid()
Dim Fso ,tf,fileName,strLine
strLine=Empty
fileName=getfolder() & "\pid.txt"
Set Fso = CreateObject("Scripting.FileSystemObject")
If Fso.fileexists(fileName)Then
'read from file
Set tf =Fso.opentextfile(fileName,1)
Do While tf.atendofstream<>True
strLine = tf.ReadLine
Loop
End If
tf.close
Set Fso = Nothing
get_last_pid=strLine
end function

function set_last_pid(pid)
Dim fso ,fw,fileName
fileName=getfolder() & "\pid.txt"
set fso=CreateObject("scripting.filesystemobject")
set fw=fso.opentextfile(fileName,2,true)
fw.writeline pid
fw.close
Set fso = Nothing
end function

sub kill_pid(pid)
' 发送强制结束信号
wscript.createObject("wscript.shell").Run "taskkill /F /PID " & pid , 0 , true
end sub

' 获取当前文件夹
function getfolder()
getfolder=left(wscript.scriptfullname,instrrev(wscript.scriptfullname,"\")-1)
end function

' 设置运行目录为当前目录
objShell.CurrentDirectory = getfolder()

last_pid=get_last_pid()
if IsEmpty(last_pid) Then
else
' 杀掉进程
kill_pid last_pid
' 等待 300 ms 避免程序文件占用
WScript.Sleep(300)
' 删除 pid.txt 文件
CreateObject("Scripting.FileSystemObject").DeleteFile(getfolder() & "\pid.txt"), True
end if

后续

可以考虑使用 NSIS 进行安装卸载 的管理。

参考文档

  • VBS中WScript.Shell对象的run和exec的使用及区别
  • WshScriptExec Object
  • Exec Method (Windows Script Host)
  • VBScript 函数
  • VBS 读写文件