Electron——如何检测应用程序的未响应状态

2024-08-16 14:52:18 浏览数 (2)

前言

我们如何通过Electron来检测一些应用程序的状态呢,如:未响应;

  • 文档地址 EnumWindows IsHungAppWindow GetWindowThreadProcessId NodeJs——如何获取Windows电脑指定应用进程信息

内容

获取指定应用程序PID

通过exec执行cmd命令查询指定应用的PID,并通过electron-store存储获取到的PID,可参考NodeJs——如何获取Windows电脑指定应用进程信息;

代码语言:javascript复制
/**
 * 获取指定应用程序的PID | 只考虑win和linux
 * @param exeName
 */
export function cmdFindPidList (exeName, callbackFun) {
  const cmd = process.platform === 'win32' ? `tasklist -V|findstr "${exeName}" ` : `ps aux | grep ${exeName}`;
  let pids = [];
  exec(cmd, (err, stdout, stderr) => {
    if (err) {
      callbackFun(pids);
      return
    }
    stdout.split('n').filter(item => {
      const p = item.trim().split(/s /)
      // p[0] 应用程序名称  p[1] 应用程序PID
      if (p[0] && p[1]) {
        pids.push(p[1]);
      }
    })
    callbackFun(pids);
  })
}

// 调用
 cmdFindPidList('App.exe', (pids) => {
      // 封装的`electron-store`存储
      setStore('AppPids', pids)
  })

调用user32.dll方法

代码语言:javascript复制
const User32 = ffi.Library('user32.dll', {
  EnumWindows: ['bool', ['pointer', 'long']],
  GetWindowThreadProcessId: ['int', ['long', 'pointer']],
  IsHungAppWindow: ['bool', ['long']]
})

const EnumWindowsProc = ffi.Callback('bool', ['long', 'int32'], function (hwnd, lParam) {
   let pids = getStore('AppPids')
   let pidBuff = Buffer.alloc(255)
   let threadId = User32.GetWindowThreadProcessId(hwnd, pidBuff)
   let pid = String(pidBuff.readInt32LE(0))
   if (pids.includes(pid) && User32.IsHungAppWindow(hwnd)) {
       // TODO 检测到程序窗口未响应处理方法
   }
  return true
})

// 调用
User32.EnumWindows(EnumWindowsProc, 0)

tasklist(推荐)

通过webworker新起一个线程进行检测

代码语言:javascript复制
import { exec } from 'child_process'
onmessage = function (e) {
  console.info(`worker: ${e.data}`)
  setInterval(() => {
    try {
      exec("tasklist /V /FI "STATUS ne RUNNING" | findstr "xxxx.exe"", (err, stdout, stderr) => {
        if (!err) {
          stdout.split('n').filter(item => {
            const p = item.trim().split(/s /)
            // p[0] 应用程序名称  p[1] 应用程序PID 断开连接的时候p[2]会话名会没有一定要注意
            if (p[0] ==='xxxx.exe' && p[1]) {
              try {
                exec(`taskkill /F /PID ${p[1]} /T`, (error, stdout, stderr) => {
                  if (!error) console.info(`worker: 清除无响应xxxx.exe成功 ===> p[0](应用名称) => ${p[0]}, p[1](应用程序PID) => ${p[1]}`)
                })
              } catch (e) {
                console.error(`worker: 清除无响应xxxx.exe失败 ===> ${e}`)
              }
            }
          })
        }
      })
    } catch (e) {
      console.error(`worker:关闭无响应xxxx.exe,${e}`)
    }
  }, 10000)
}

BAT脚本

代码语言:javascript复制
@echo off
:start

:: 检测状态为未相应的应用进程 | 所有不理解的命令均可通过帮助进行查看,示例如下
:: for /?

for /f "skip=3 tokens=2 " %%i in ('tasklist /V /FI "STATUS ne RUNNING" /FI "imageNAME eq xxx.exe"') do (
 ::日志输出文件主要看bat启动位置
 echo "�te% %time% 记录无响应的应用进程PID: %%i" >> "exeStatus.txt"
 for /f "tokens=3* delims=: " %%j in ('find /C "%%i" exeStatus.txt') do (
       ::大于3次
       if %%j GTR 3 (
		echo "�te% %time% 开始清除出现%%j次无响应的应用进程PID: %%i">> "DelExePid.txt"
		taskkill /F /PID %%i /T >> "DelExePid.txt"
		findstr /V %%i "exeStatus.txt" > "exeStatus.tmp"
		move /Y exeStatus.tmp exeStatus.txt
	)
 )
)
::10s检测一次
choice /t 10 /d y /n > null
goto start

0 人点赞