如何检查应用程序是否从批处理(好cmd)文件运行?

如果程序已经在运行,我不需要启动另一个实例。(我不能改变应用程序,使它只有单一实例。)

此外,应用程序可以作为任何用户运行。


当前回答

我需要一个重试的解决方案。这段代码将一直运行,直到找到进程,然后将其终止。你可以设置一个超时或任何你喜欢的东西。

注:

“。exe”是必选项 你可以让一个文件运行参数,版本如下

    :: Set programm you want to kill
    :: Fileextension is mandatory
    SET KillProg=explorer.exe

    :: Set waiting time between 2 requests in seconds
    SET /A "_wait=3"

    :ProcessNotFound
        tasklist /NH /FI "IMAGENAME eq %KillProg%" | FIND /I "%KillProg%"
        IF "%ERRORLEVEL%"=="0" (
            TASKKILL.EXE /F /T /IM %KillProg%
        ) ELSE (
            timeout /t %_wait%
            GOTO :ProcessNotFound
        )

taskkill.bat:

    :: Get program name from argumentlist
    IF NOT "%~1"=="" (
        SET "KillProg=%~1"
    ) ELSE (
        ECHO Usage: "%~nx0" ProgramToKill.exe & EXIT /B
    )

    :: Set waiting time between 2 requests in seconds
    SET /A "_wait=3"

    :ProcessNotFound
        tasklist /NH /FI "IMAGENAME eq %KillProg%" | FIND /I "%KillProg%"
        IF "%ERRORLEVEL%"=="0" (
            TASKKILL.EXE /F /T /IM %KillProg%
        ) ELSE (
            timeout /t %_wait%
            GOTO :ProcessNotFound
        )

使用。\taskkill.bat ProgramToKill.exe运行

其他回答

我假设这里是窗户。因此,您需要使用WMI来获取该信息。查看脚本编写者的档案,有很多关于如何从脚本中使用WMI的示例。

你应该检查父进程名,参见代码项目中关于基于。net解决方案的文章**。

一种非编程的检查方法:

发射用于cmd . exe 启动一个应用程序(例如,c:\windows\notepad.exe) 在进程资源管理器中检查“Notepad.exe”进程的属性 检查父进程(显示cmd.exe)

同样可以通过获取父进程名进行检查。

我喜欢WMIC和TASKLIST工具,但是在windows的家庭/基本版本中没有。另一种方法是在几乎所有windows机器上使用QPROCESS命令(对于那些有终端服务的机器-我认为只有XP没有SP2,所以几乎所有windows机器):

@echo off
:check_process
setlocal
if "%~1" equ "" echo pass the process name as forst argument && exit /b 1
:: first argument is the process you want to check if running
set process_to_check=%~1
:: QPROCESS can display only the first 12 symbols of the running process
:: If other tool is used the line bellow could be deleted
set process_to_check=%process_to_check:~0,12%

QPROCESS * | find /i "%process_to_check%" >nul 2>&1 && (
    echo process %process_to_check%  is running
) || (
    echo process %process_to_check%  is not running
)
endlocal

QPROCESS命令没有TASKLIST那么强大,只能显示12个进程名符号,但如果TASKLIST不可用,则应考虑使用QPROCESS命令。

更简单的用法,它使用进程名作为参数(在这种情况下,当你传递可执行名称时,.exe后缀是必选的):

@echo off
:check_process
setlocal
if "%~1" equ "" echo pass the process name as forst argument && exit /b 1
:: first argument is the process you want to check if running
:: .exe suffix is mandatory
set "process_to_check=%~1"


QPROCESS "%process_to_check%" >nul 2>&1 && (
    echo process %process_to_check%  is running
) || (
    echo process %process_to_check%  is not running
)
endlocal

QPROCESS的两种使用方式的区别是,QPROCESS *将列出所有进程,而QPROCESS some.exe将仅为当前用户过滤进程。

通过windows脚本主机exe而不是WMIC使用WMI对象也是一种选择。它还应该在每台windows机器上运行(不包括关闭WSH的机器,但这种情况很少见)。下面是一个通过WMI类列出所有进程的bat文件,可以用来代替上面脚本中的QPROCESS(它是jscript/bat的混合体,应该保存为.bat):

@if (@X)==(@Y) @end /* JSCRIPT COMMENT **


@echo off
cscript //E:JScript //nologo "%~f0"
exit /b

************** end of JSCRIPT COMMENT **/


var winmgmts = GetObject("winmgmts:\\\\.\\root\\cimv2");
var colProcess = winmgmts.ExecQuery("Select * from Win32_Process");
var processes =  new Enumerator(colProcess);
for (;!processes.atEnd();processes.moveNext()) {
    var process=processes.item();
    WScript.Echo( process.processID + "   " + process.Name );
}

以及检查进程是否正在运行的修改:

@if (@X)==(@Y) @end /* JSCRIPT COMMENT **


@echo off
if "%~1" equ "" echo pass the process name as forst argument && exit /b 1
:: first argument is the process you want to check if running
set process_to_check=%~1

cscript //E:JScript //nologo "%~f0" | find /i "%process_to_check%" >nul 2>&1 && (
    echo process %process_to_check%  is running
) || (
    echo process %process_to_check%  is not running
)

exit /b

************** end of JSCRIPT COMMENT **/


var winmgmts = GetObject("winmgmts:\\\\.\\root\\cimv2");
var colProcess = winmgmts.ExecQuery("Select * from Win32_Process");
var processes =  new Enumerator(colProcess);
for (;!processes.atEnd();processes.moveNext()) {
    var process=processes.item();
    WScript.Echo( process.processID + "   " + process.Name );
}

这两个选项可以在没有TASKLIST的机器上使用。

最终的技术是使用MSHTA。这将运行在每一台windows机器从XP和以上,不依赖于windows脚本主机设置。调用MSHTA可能会降低一些性能(同样应该保存为bat):

@if (@X)==(@Y) @end /* JSCRIPT COMMENT **
@echo off

setlocal
if "%~1" equ "" echo pass the process name as forst argument && exit /b 1
:: first argument is the process you want to check if running

set process_to_check=%~1


mshta "about:<script language='javascript' src='file://%~dpnxf0'></script>" | find /i "%process_to_check%" >nul 2>&1 && (
    echo process %process_to_check%  is running
) || (
    echo process %process_to_check%  is not running
)
endlocal
exit /b
************** end of JSCRIPT COMMENT **/


   var fso= new ActiveXObject('Scripting.FileSystemObject').GetStandardStream(1);


   var winmgmts = GetObject("winmgmts:\\\\.\\root\\cimv2");
   var colProcess = winmgmts.ExecQuery("Select * from Win32_Process");
   var processes =  new Enumerator(colProcess);
   for (;!processes.atEnd();processes.moveNext()) {
    var process=processes.item();
    fso.Write( process.processID + "   " + process.Name + "\n");
   }
   close();

我使用了Matt提供的脚本。我唯一遇到的麻烦是它不能删除search.log文件。我想是因为我必须cd到另一个位置来启动我的程序。我cd回BAT文件和search.log所在的位置,但它仍然不能删除。所以我首先删除了search.log文件,而不是最后删除。

del search.log

tasklist /FI "IMAGENAME eq myprog.exe" /FO CSV > search.log

FOR /F %%A IN (search.log) DO IF %%-zA EQU 0 GOTO end

cd "C:\Program Files\MyLoc\bin"

myprog.exe myuser mypwd

:end

我提出的另一种可能,不需要保存文件,灵感来自于使用grep:

tasklist /fi "ImageName eq MyApp.exe" /fo csv 2>NUL | find /I "myapp.exe">NUL
if "%ERRORLEVEL%"=="0" echo Program is running

/fi ""定义了一个应用程序的过滤器,在我们的例子中,它是*.exe名称 CSV定义了输出格式,CSV是必需的,因为默认情况下,如果可执行文件的名称太长,它可能会被截断,从而无法被稍后的find匹配。 find /I表示不区分大小写的匹配,可以省略

有关整个语法,请参阅tasklist命令的手册页。