Skip to content

Commit 0843977

Browse files
committed
优化:获取 Windows 进程信息的函数,并不再依赖 PowerShell。Optimization: Get Windows process information functions
, no longer rely on PowerShell.
1 parent da41dde commit 0843977

File tree

9 files changed

+95
-73
lines changed

9 files changed

+95
-73
lines changed

electron-builder.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,19 @@ appId: net.XianYun.EServer
22
productName: EServer
33
files:
44
- '!**/.vscode/*'
5+
- "!**/node_modules/*/{CHANGELOG.md,README.md,README,readme.md,readme}"
6+
- "!**/node_modules/*/{test,__tests__,tests,powered-test,example,examples}"
7+
- "!**/node_modules/*.d.ts"
8+
- "!**/node_modules/.bin"
59
- '!src/*'
610
- '!electron.vite.config.{js,ts,mjs,cjs}'
711
- '!{.eslintignore,.eslintrc.cjs,.prettierignore,.prettierrc.yaml,dev-app-update.yml,CHANGELOG.md,README.md}'
812
- '!{.env,.env.*,.npmrc,pnpm-lock.yaml}'
913
- '!{tsconfig.json,tsconfig.node.json,tsconfig.web.json}'
1014
- '!extra/*'
1115
- '!screenshots/*'
16+
- '!node_modules/koffi/build/koffi/!(win32_*64)'
17+
1218
mac:
1319
target:
1420
- target: dmg
@@ -40,6 +46,8 @@ win:
4046
extraFiles:
4147
- from: extra/win32/EServerService.exe
4248
to: EServerService.exe
49+
- from: extra/win32/windowsapi.dll
50+
to: windowsapi.dll
4351
- from: ./extra/win32/core/config/
4452
to: ./core/config/
4553
- from: ./extra/win32/core/initFiles/

electron.vite.config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { AntDesignVueResolver } from 'unplugin-vue-components/resolvers'
77
import { builtinModules } from 'module'
88

99
const externals = ['fix-path', 'electron-store', 'extract-zip',
10-
'hmc-win32', 'net-win32', '@napi-rs/lzma',...builtinModules, ...builtinModules.map((m) => `node:${m}`)]
10+
'hmc-win32', 'net-win32', '@napi-rs/lzma','koffi',...builtinModules, ...builtinModules.map((m) => `node:${m}`)]
1111

1212
export default defineConfig({
1313
main: {

extra/win32/windowsapi.dll

4.25 MB
Binary file not shown.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
"extract-zip": "^2.0.1",
2929
"fix-path": "^3.0.0",
3030
"hmc-win32": "~1.4.92",
31+
"koffi": "^2.14.1",
3132
"net-win32": "^1.0.1",
3233
"semver-diff": "3.1.1",
3334
"tar": "^7.4.3",
@@ -44,7 +45,7 @@
4445
"electron": "^22.3.27",
4546
"electron-builder": "^24.9.1",
4647
"electron-devtools-installer": "^3.2.0",
47-
"electron-vite": "^2.1.0",
48+
"electron-vite": "^2.3.0",
4849
"eslint": "^8.47.0",
4950
"eslint-plugin-vue": "^9.33.0",
5051
"less": "^4.2.0",

src/main/helpers/constant.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ export const SETTINGS_FILE_NAME = 'settings.json'
1313
export const CONF_INDENT = ' '
1414

1515
export const PowerShell = 'powershell'
16+
export const WINDOWS_API_FILE_NAME = 'windowsapi.dll'
1617

1718
export const ChildAppTypes = {
1819
PHP: 'PHP',

src/main/utils/ProcessExtend.js

Lines changed: 69 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,18 @@
11
import Command from '@/main/utils/Command'
22
import { isMacOS, isWindows } from '@/shared/utils/utils2'
3-
import { PowerShell } from '@/main/helpers/constant'
4-
import OS from '@/main/utils/OS'
3+
import { PowerShell, WINDOWS_API_FILE_NAME } from '@/main/helpers/constant'
4+
import nodePath from 'path'
5+
import GetCorePath from '@/shared/helpers/GetCorePath'
56

67
export default class ProcessExtend {
8+
static _ffiModule = null;
9+
static _initFfi(){
10+
if(!ProcessExtend._ffiModule){
11+
ProcessExtend._ffiModule = require('koffi')
12+
ProcessExtend._ffiModule.config({max_async_calls:256})
13+
}
14+
return ProcessExtend._ffiModule
15+
}
716
/**
817
* 杀死进程和子进程
918
* @param pid {number}
@@ -22,14 +31,12 @@ export default class ProcessExtend {
2231
}
2332
if (isWindows) {
2433
//taskkill杀不存在的进程会有标准错误,从而引发异常
25-
await Command.exec(`taskkill /f /t /pid ${pid}`);
34+
await Command.exec(`taskkill /f /t /pid ${pid}`)
2635
} else {
27-
await Command.sudoExec(`kill ${pid}`);
36+
await Command.sudoExec(`kill ${pid}`)
2837
}
2938
// eslint-disable-next-line no-empty
30-
} catch {
31-
32-
}
39+
} catch {}
3340
}
3441

3542
static async getParentPid(pid) {
@@ -57,57 +64,36 @@ export default class ProcessExtend {
5764
try {
5865
if (isWindows) {
5966
//taskkill杀不存在的进程会有标准错误,从而引发异常
60-
await Command.exec(`taskkill /f /t /im ${name}.exe`);
67+
await Command.exec(`taskkill /f /t /im ${name}.exe`)
6168
} else {
6269
//pkill杀不存在的进程会有标准错误,从而引发异常
63-
await Command.sudoExec(`pkill ${name}`);
70+
await Command.sudoExec(`pkill ${name}`)
6471
}
6572
// eslint-disable-next-line no-empty
66-
} catch {
67-
68-
}
73+
} catch {}
6974
}
7075

7176
static pidIsRunning(pid) {
7277
try {
73-
process.kill(pid, 0);
74-
return true;
78+
process.kill(pid, 0)
79+
return true
7580
} catch (e) {
76-
return false;
81+
return false
7782
}
7883
}
7984

8085
/**
81-
* 根据pid,获取进程路径。Windows下,winShell=false,不支持并发,但是速度快。winShell=true,支持并发,但是速度慢。
86+
* 根据pid,获取进程路径
8287
* @param pid {number}
83-
* @param winShell {boolean}
8488
* @returns {Promise<*|null>}
8589
*/
86-
static async getPathByPid(pid, winShell = false) {
90+
static async getPathByPid(pid) {
8791
try {
8892
pid = parseInt(pid)
8993
let path
9094

9195
if (isWindows) {
92-
if (winShell) {
93-
const versionStr = OS.getVersion()
94-
const [major, minor, build] = versionStr.split('.').map(Number)
95-
if (major === 10 && build >= 22000) {
96-
//Windows 11: 版本号从 10.0.22000 开始。Windows11 废弃了 wmic
97-
const commandStr = `(Get-Process -Id ${pid}).MainModule.FileName`
98-
const resStr = await Command.exec(commandStr, { shell: PowerShell })
99-
path = resStr.trim().split('\n')[0]
100-
} else {
101-
const commandStr = `wmic process where processid=${pid} get executablepath`
102-
const resStr = await Command.exec(commandStr)
103-
path = resStr.trim().split('\n')[1]
104-
}
105-
} else {
106-
const hmc = require('hmc-win32')
107-
path = await hmc.getProcessFilePath2(pid) //getProcessFilePath2暂不支持并发
108-
path = path ?? ''
109-
path = path.startsWith('\\Device\\HarddiskVolume') ? '' : path //过滤掉 getProcessFilePath2 错误的path
110-
}
96+
path = await ProcessExtend.getPathByPidForWindows(pid)
11197
} else {
11298
const commandStr = `lsof -p ${pid} -a -w -d txt -Fn|awk 'NR==3{print}'|sed "s/n//"`
11399
const resStr = await Command.exec(commandStr)
@@ -120,18 +106,47 @@ export default class ProcessExtend {
120106
}
121107
}
122108

109+
static async getNameByPidForWindows(pid) {
110+
try {
111+
const koffi = ProcessExtend._initFfi()
112+
const libPath = nodePath.join(GetCorePath.getParentDir(), WINDOWS_API_FILE_NAME)
113+
const lib = koffi.load(libPath)
114+
const getProcessName = lib.func('getProcessName', 'str', ['int'])
115+
// 个别进程的 getProcessName 比 getProcessPath 更耗时
116+
return await new Promise((resolve, reject) => {
117+
getProcessName.async(pid, (err, res) => {
118+
resolve(res ?? '')
119+
})
120+
})
121+
}catch(e){
122+
return null
123+
}
124+
}
125+
126+
static async getPathByPidForWindows(pid) {
127+
try {
128+
const koffi = ProcessExtend._initFfi()
129+
const libPath = nodePath.join(GetCorePath.getParentDir(), WINDOWS_API_FILE_NAME)
130+
const lib = koffi.load(libPath)
131+
const getProcessPath = lib.func('getProcessPath', 'str', ['int'])
132+
return getProcessPath(pid)
133+
}catch{
134+
return null
135+
}
136+
}
137+
123138
/**
124139
*
125140
* @param options {object}
126141
* @returns {Promise<[]|{path: *, name: *, pid: *, ppid: *}[]>}
127142
*/
128-
static async getList(options={}) {
143+
static async getList(options = {}) {
129144
if (isMacOS) {
130-
return await this.getListForMacOS(options);
145+
return await this.getListForMacOS(options)
131146
} else if (isWindows) {
132-
return await this.getListForWindows(options);
147+
return await this.getListForWindows(options)
133148
}
134-
return [];
149+
return []
135150
}
136151

137152
static async getListForMacOS(options = {}) {
@@ -150,24 +165,22 @@ export default class ProcessExtend {
150165
command += `|grep -F -v '.dylib'|awk '{print $1,$2,$3,$10}'`
151166
try {
152167
let str = await Command.sudoExec(command)
153-
str = str.trim();
154-
if(!str){
155-
return [];
168+
str = str.trim()
169+
if (!str) {
170+
return []
156171
}
157-
let list = str.split('\n');
172+
let list = str.split('\n')
158173

159-
list = list.map(item => {
160-
let arr = item.split(' ');
161-
let name, pid, ppid, path;
162-
[name, pid, ppid, path] = arr;
163-
return {name, pid, ppid, path};
164-
});
174+
list = list.map((item) => {
175+
let arr = item.split(' ')
176+
const [name, pid, ppid, path] = arr
177+
return { name, pid, ppid, path }
178+
})
165179

166-
return list;
180+
return list
167181
} catch (e) {
168182
return []
169183
}
170-
171184
}
172185

173186
static async getListForWindows(options = {}) {
@@ -188,15 +201,14 @@ export default class ProcessExtend {
188201
return []
189202
}
190203
let list = str.split(/\r?\n\r?\n/)
191-
list = list.map(item => {
204+
list = list.map((item) => {
192205
let lineArr = item.split(/\r?\n/)
193206

194-
let arr = lineArr.map(line => {
207+
let arr = lineArr.map((line) => {
195208
return line.split(' : ')[1]?.trim()
196209
})
197210

198-
let name, pid, ppid, path;
199-
[name, pid, ppid, path] = arr
211+
const [name, pid, ppid, path] = arr
200212
return { name, pid, ppid, path }
201213
})
202214
return list

src/main/utils/TcpProcess.js

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -76,21 +76,18 @@ export default class TcpProcess {
7676

7777
static async getListForWindows() {
7878
const net = require('net-win32')
79-
const hmc = require('hmc-win32')
8079
try {
8180
let list = await net.getConnectNetListAsync(true, false, true, false)
8281
list = await list.filterAsync((item) => item.state === 'LISTEN')
83-
//由于hmc的promise暂不支持并发,所以先用for of
84-
const result = []
85-
for (const item of list) {
86-
const { pid, ip, port } = item
87-
const name = await hmc.getProcessName2(pid)
88-
const path = await ProcessExtend.getPathByPid(pid)
89-
const icon = path ? await getFileIcon(path) : null
90-
result.push({ pid, ip, port, name, path, status: 'Listen', icon })
91-
}
92-
93-
return result
82+
return await Promise.all(
83+
list.map(async (item) => {
84+
const { pid, ip, port } = item
85+
const name = await ProcessExtend.getNameByPidForWindows(pid)
86+
const path = await ProcessExtend.getPathByPidForWindows(pid)
87+
const icon = path ? await getFileIcon(path) : null
88+
return { pid, ip, port, name, path, status: 'Listen', icon }
89+
})
90+
)
9491
} catch (e) {
9592
return []
9693
}

src/shared/helpers/GetCorePath.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { isDev, isMacOS, isWindows } from '@/shared/utils/utils2'
22
import path from 'path'
33
import ChildApp from '@/main/services/childApp/ChildApp'
4-
import { INIT_FILE_NAME, CoreDirNames, INSTALL_OR_UPDATE_FILE_NAME } from '@/main/helpers/constant'
4+
import { CoreDirNames, INSTALL_OR_UPDATE_FILE_NAME } from '@/main/helpers/constant'
55
import GetAppPath from '@/shared/helpers/GetAppPath'
66
import process from 'process'
77

@@ -19,6 +19,10 @@ export default class GetCorePath {
1919
}
2020
}
2121

22+
static getParentDir() {
23+
return path.dirname(GetCorePath.getDir())
24+
}
25+
2226
//用来第一次安装或者覆盖安装更新
2327
static getInstallOrUpdateFilePath() {
2428
return path.join(this.getDir(), INSTALL_OR_UPDATE_FILE_NAME)

src/shared/helpers/constant.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ export const OFFICIAL_HOST = 'eserver.devcn.top'
33
export const OFFICIAL_URL = `http://${OFFICIAL_HOST}`
44
export const DOWNLOAD_URL = 'http://dl.eserver.devcn.top'
55
export const SERVICE_NAME = 'EServerService'
6-
export const SETTINGS_FILE_NAME = 'settings.json'
76

87
export const colorConst = {
98
light: {

0 commit comments

Comments
 (0)