0

I am running a process from a vbsscript and I want it to run indefinitely in the background. It works as expected for a while and shuts itself off. If I open the batch file directly it won't stop at all which is the behavior I want, but in the background. This is the code I use to make it run.

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

*Edit I thought I might have more luck if I added the script.

@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

*Edit 2 Logging produced the issue

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

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

This eventually causes problems on the stack which are explained nicely here: http://www.experts-exchange.com/OS/Microsoft_Operating_Systems/MS_DOS/Q_27500205.html I'll be working on a solution for my case which does not require the overhead of re-executing a new batch file instead of looping-- if that does cause additional overhead as I believe it would. If someone beats me to it that'd be great though. ^.^

Gage Ervin
  • 105
  • 1
  • 8
  • Not really super helpful but since no one seems to know: When you say it runs for a while as expected it seems to me as if only one special case is not working. My suspicion would be the iskeydown check, which sounds most like something that would break if there is no gui. To be sure I would add some logging for each step so that you can see what works and what the last thing before it stops is. On a side note: are you not afraid that constantly checking for the battery drains it a lot in the first place? – Syberdoor Sep 14 '15 at 05:50
  • To your first question, the check works because whenever I hit the keys my other script starts; however, it seems like a good idea to use logging to see if it terminates consistently at some point; I will try that and update this post later. As to the second, I'm not sure how frequently windows itself checks the battery to support its taskbar icon but this script only updates once per second. I'm also not sure rather my check just gets the most recent windows information or actually forces it to update. – Gage Ervin Sep 14 '15 at 07:14

2 Answers2

1

:: if not notified comment could cause unexpected behaviour: absolutely never use :label nor :: label-like comment inside a command block enclosed in () parentheses. See this my answer for proof.

call :BATUPDATE "%%b" will cause stack overflow sooner or later, of course. In fact, your script logic is as follows (simplified: never returns from the subroutine which calls itself recursively):

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

The CALL command will pass control to the statement after the label specified along with any specified parameters. To exit the subroutine specify GOTO:eof this will transfer control back to the statement after the appropriate CALL (excerpted roughly from CALL: Call one batch program from another, or call a subroutine). See also GOTO: Direct a batch program to jump to a labelled line.

Hence, improve your script logic as follows:

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

:BATUPDATE
  rem some BATUPDATE code: use %~1
GOTO :eof
Community
  • 1
  • 1
JosefZ
  • 28,460
  • 5
  • 44
  • 83
0

As JosefZ mentioned, it's fatal that you call a label just behind your loop without properly returning, this will fill the call stack and should result in a stack overflow after 300-700 nested calls.

It's always better to call functions and return at the end instead of using goto to jump around.

Use debugging to see your variables like cycleLen, it's not 7 instead the content is 6+1 which will not produce errors, but it will expands later in

set /a num = 100 / %cycleLen%

to

set /a num = 100 / 6 + 1
jeb
  • 78,592
  • 17
  • 171
  • 225