为什么我的控制台进程会一直停止并且如何阻止它?

时间:2015-09-11 22:55:46

标签: windows batch-file vbscript

我正在从vbsscript运行一个进程,我希望它在后台无限期运行。它按预期工作了一段时间并关闭。如果我直接打开批处理文件,它根本不会停止,这是我想要的行为,但在后台。这是我用来运行它的代码。

Dim WinScriptHost
Set WinScriptHost = CreateObject("WScript.Shell")
WinScriptHost.Run Chr(34) & "C:\hackish\beHackish.bat" & Chr(34), 0
Set WinScriptHost = Nothing

*编辑我想如果我添加剧本,我可能会有更多的运气。

@ECHO OFF

taskkill /IM explorer.exe /F
Start loadAliases.bat

setlocal

set multipleNotification=3
set BatteryLevel=-1
set notificationThreshold=15
set hasBatteryNotified=0
set cycleLen=6
set alternator=0

:: increment length bc of division
set cycleLen=%cycleLen%+1

:LOOP
    :: pausing
    TIMEOUT /T 1 /NOBREAK > nul

    :: if on battery
    for /F "delims== tokens=1,2" %%a in ('WMIC Path Win32_Battery Get BatteryStatus /format:textvaluelist.xsl') do @if "BatteryStatus"=="%%a" call :BATUPDATE "%%b"
    :BATUPDATE
    set /a alternator=!%alternator%
    if  %~1 NEQ 2 (
        goto DISCHARGING
    ) else (
        goto CHARGING
    )
    :CONTINUE3

    :: check custom hotkey (bc windows doesn't work right)
    keyCheck\isKeyDown.exe 11
    IF errorlevel 1 GOTO CHECKT

GOTO LOOP

:CHECKT
    keyCheck\isKeyDown.exe 09
    IF errorlevel 1 Start loadAliases.bat
GOTO LOOP

:DISCHARGING
    echo discharging

    :: if battery level low, notify
    for /f %%a in ('wmic.exe path Win32_Battery get EstimatedChargeRemaining ^| findstr.exe /r "[0-9][0-9]*"') do set BatteryLevel=%%a
    set /a notMultiple = %BatteryLevel% %% %multipleNotification%
    if %BatteryLevel% leq %notificationThreshold% if %notMultiple% == 0 (

        :: if not notified
        if %hasBatteryNotified% == 0 (
            start cmd /K echo Batery is at %BatteryLevel%!!
            set hasBatteryNotified=1
        )
    ) else (
        set hasBatteryNotified=0
    )

    :: update wallpaper cycle
    set /a num = 100 / %cycleLen%
    set /a num = %BatteryLevel% / num
    SET wallPath="C:\\hackish\desktops\pics\0%num%%alternator%.bmp"
    desktops\Project1.exe %wallPath%
GOTO CONTINUE3


:CHARGING
    echo charging

    set hasBatteryNotified=0

    :: update wallpaper cycle

    for /f %%a in ('wmic.exe path Win32_Battery get EstimatedChargeRemaining ^| findstr.exe /r "[0-9][0-9]*"') do set BatteryLevel=%%a
    set /a num = 100 / %cycleLen%
    set /a num = %BatteryLevel% / num
    SET wallPath="C:\\hackish\desktops\pics\1%num%%alternator%.bmp"
    desktops\Project1.exe %wallPath%
GOTO CONTINUE3

*编辑2记录产生了问题

for / F" delims == tokens = 1,2" %% a in(' WMIC Path Win32_Battery Get

BatteryStatus /format:textvaluelist.xsl') do @if "BatteryStatus"=="%%a" call :BATUPDATE "%%b"

这最终导致堆栈出现问题,这里有很好的解释:http://www.experts-exchange.com/OS/Microsoft_Operating_Systems/MS_DOS/Q_27500205.html我正在为我的案例开发一个解决方案,它不需要重新执行新批处理文件的开销而不是循环 - 如果这确实会导致额外的开销,我相信它会。如果有人打败我,那会很棒。 ^。^

2 个答案:

答案 0 :(得分:1)

:: if not notified评论可能导致意外行为:绝对从不在命令块中使用:label:: label-like comment < / em>括在()个括号中。有关证据,请参阅this my answer

当然,

call :BATUPDATE "%%b" 会迟早导致堆栈溢出。实际上,您的脚本逻辑如下(简化:永远不会从递归调用自身的子例程返回):

:LOOP
  call :BATUPDATE "%random%"
  :BATUPDATE
  rem some BATUPDATE code: use %~1
GOTO :LOOP

CALL命令会在指定的标签和任何指定参数之后将控制传递给语句。要退出子例程,请指定GOTO:eof,这会将控制权转移回适当的CALL之后的语句(大致从CALL: Call one batch program from another, or call a subroutine摘录)。另请参阅GOTO: Direct a batch program to jump to a labelled line

因此,改进您的脚本逻辑如下:

:LOOP
  call :BATUPDATE "%random%"
GOTO :LOOP

:BATUPDATE
  rem some BATUPDATE code: use %~1
GOTO :eof

答案 1 :(得分:0)

正如JosefZ所提到的那样,如果你没有正确返回就在你的循环后面调用一个标签是致命的,这将填满调用堆栈,并且应该在300-700次嵌套调用之后导致堆栈溢出。

总是更好地调用函数并在最后返回,而不是使用goto来跳转。

使用调试来查看cycleLen之类的变量,它不是7而是内容为6+1,这不会产生错误,但会在以后扩展

set /a num = 100 / %cycleLen%

set /a num = 100 / 6 + 1