1

I am trying to convert a batch file to VBS. This is what I have so far. Looking for advice on proper formatting, as well as any help as to why this VBS script isn't working at the moment. Here's what I've got so far:

OPTION EXPLICIT
DIM strComputer,strSCVA,strDOSBox

strComputer = "." ' local computer
strSCVA = "scva.exe"
strDOSBox = "dosbox.exe"

' Check if scva.exe is running at startup (. = local computer)
IF isProcessRunning(strComputer,strSCVA) THEN
    Call LoopStart
ELSE
    cd "%~dp0../"
    start /min "" "scva.exe"
    Call LoopStart
END IF

Sub LoopStart
' Exits script if scva.exe is manually terminated, otherwise, calls CheckDOSBox
IF isProcessRunning(strComputer,strSCVA) THEN
    Call CheckDOSBox
ELSE
    WScript.Quit
END IF

Sub CheckDOSBox
' Goes to LoopStart while dosbox.exe is running, otherwise, calls Kill
IF isProcessRunning(strComputer,strDOSBox) THEN
    Call LoopStart
ELSE
    Call Kill
END IF

Sub Kill
' Sends command to terminate scva.exe while scva.exe is running, otherwise, exits script
IF isProcessRunning(strComputer,strSCVA) THEN
    taskkill /IM scva.exe
    Call Kill
ELSE
    WScript.Quit
END IF

' Function to check if a process is running
FUNCTION isProcessRunning(BYVAL strComputer,BYVAL strProcessName)

    DIM objWMIService, strWMIQuery

    strWMIQuery = "Select * from Win32_Process where name like '" & strProcessName & "'"

    SET objWMIService = GETOBJECT("winmgmts:" _
        & "{impersonationLevel=impersonate}!\\" _ 
            & strComputer & "\root\cimv2") 


    IF objWMIService.ExecQuery(strWMIQuery).Count > 0 THEN
        isProcessRunning = TRUE
    ELSE
        isProcessRunning = FALSE
    END IF

END FUNCTION

And here's the original batch file that's being converted (which I also wrote):

REM Runs scva.exe if it is not running; kills process after dosbox.exe is terminated

tasklist /FI "IMAGENAME eq scva.exe" 2>NUL | find /I /N "scva.exe">NUL
if "%ERRORLEVEL%"=="0" (
    goto LoopStart
) else (
    cd "%~dp0../"
    start /min "" "scva.exe"
    goto LoopStart
)

:LoopStart
REM Exits script if scva.exe is manually terminated, otherwise, goes to CheckDOSBox

tasklist /FI "IMAGENAME eq scva.exe" 2>NUL | find /I /N "scva.exe">NUL
if "%ERRORLEVEL%"=="0" (
    goto CheckDOSBox
) else (
    exit
)

:CheckDOSBox
REM Goes to LoopStart while dosbox.exe is running, otherwise, goes to Kill

tasklist /FI "IMAGENAME eq dosbox.exe" 2>NUL | find /I /N "dosbox.exe">NUL
if "%ERRORLEVEL%"=="0" (
    goto LoopStart
) else (
    goto Kill
)

:Kill
REM Sends command to terminate scva.exe while scva.exe is running, otherwise, exits script

tasklist /FI "IMAGENAME eq scva.exe" 2>NUL | find /I /N "scva.exe">NUL
if "%ERRORLEVEL%"=="0" (
    taskkill /IM scva.exe
    goto Kill
)
exit

I think that my problem area is not knowing how to properly start a program in VBS. I have googled this but I don't understand the implementation and it would help if someone could show me how it works in my own code. Additionally, what is the equivalent of cd "%~dp0../" in VBS? In other words, the equivalent to relatively setting the working directory to the current directory of the VBS script?

Lucas
  • 57
  • 5
  • I think this might be the first "how do I convert this code" question I've seen on here that's actually _good_. – SomethingDark Jun 05 '17 at 03:59
  • Also, I see two sub declarations, but no `end sub`s. Admittedly, my only VB* experience is with VBA, but I'm pretty sure you need those. – SomethingDark Jun 05 '17 at 04:00

2 Answers2

2

I guess I'll post my reservations first, then see if I can actually help.

It looks like the batch file works fine - why would you want to change it to vbscript?

Ok, enough of that.

When I wrote vbscript, I'd put the subroutines at the top, and the main logic at the bottom. I'm not sure if that's what everyone does, but what it means is that I can scan down the program, see FUNCTION isProcessRunning, understand that dozen or so lines, and then carry on. This means that when I reach the part where it's called I already understand what it's for and roughly what it'll do.

The closest thing to cd that I've come across with vbscript is the WScript.CurrentDirectory property. http://www.vbsedit.com/html/a36f684c-efef-4069-9102-21b3d1d55e9e.asp Personally, I don't tend to use it, because I generally write a batch file to launch my vb scripts anyway, and I'd cd to the right place in that, if necessary.

e.g. I have a listmounts.bat which is basically:

cscript %~dp0\listmounts.vbs 

I do that because I do lots of stuff in the shell, and like this, to launch it, I just type listmounts to run it, instead of cscript \path\to\listmounts.vbs. But that's just me.

Call in vbscript works very differently from goto in a batch file. Call expects to call a subroutine or function (like IsProcessRunning) and reach the end of that subroutine, then it returns to where it was called from. That's obviously not how goto works in the batch file. Each time you do call it uses up some memory managing where you called from, and when it returns, it reclaims that memory. So with what you've set up, with the cross-over of calls, you'll probably eventually run out of memory, if it runs long enough. Might take a while though.

So here's how I'd structure it. You'll have to tweak it to make it work (partly because I have neither svca or dosbox on my machine, and partly because I'm running Linux ATM and can't test it at all).

OPTION EXPLICIT
DIM strComputer,strSCVA,strDOSBox


' start scva if it's not already running.  Kill it if dosbox dies.
' Author: Lucas 5 June 2017


' Function to check if a process is running
FUNCTION isProcessRunning(BYVAL strComputer,BYVAL strProcessName)

    DIM objWMIService, strWMIQuery

    strWMIQuery = "Select * from Win32_Process where name like '" & strProcessName & "'"

    SET objWMIService = GETOBJECT("winmgmts:" _
        & "{impersonationLevel=impersonate}!\\" _ 
            & strComputer & "\root\cimv2") 


    IF objWMIService.ExecQuery(strWMIQuery).Count > 0 THEN
        isProcessRunning = TRUE
    ELSE
        isProcessRunning = FALSE
    END IF

END FUNCTION


' kill the svca executable.
SUB KillSvca() 

    ' Keep trying to kill scva until it actually has exited.
    WHILE isProcessRunning(strComputer,strSCVA) 
        ' this won't actually work - see below for an alternative
        taskkill /IM scva.exe
    WEND
END SUB     

' ------  MAIN PROGRAM ----    


strComputer = "." ' local computer
strSCVA = "scva.exe"
strDOSBox = "dosbox.exe"

' Start SCVA if it's not already running.

IF NOT isProcessRunning(strComputer,strSCVA) THEN
    ' As above, I'd make sure it's in the correct folder first
    cd "%~dp0../"
    ' And this won't work either. see below.
    start /min "" "scva.exe"
END IF

WHILE isProcessRunning (strComputer, strSCVA) 

    IF NOT isProcessRunning(strComputer,strDOSBox) THEN
        KIllScva
    END IF

WEND

A couple of points:

GregHNZ
  • 7,946
  • 1
  • 28
  • 30
  • Thanks! Instead of using Call KillScva, Do I just put "KillScva" and it will work? In other words just leave off the "call" part? Also, the batch file does work well. However, I have an issue which is somewhat hard to explain. I may make a short video detailing the issue, because I think it's much easier to explain that way than via text, especially when you can see it happening in action. I'll reply again if I do this. Perhaps the problem can be addressed another way without having to convert my batch file to VBS. Is the formatting of that batch file correct? – Lucas Jun 05 '17 at 04:55
  • Yes, I think `call` is unnecessary, looking at the one `sub` I've got in the listmounts.vbs file I have here. – GregHNZ Jun 05 '17 at 04:57
1

This doesn't answer your question, it is a rewritten batch file to hopefully replicate my assessment of what you intend your vbscript to do:

@Echo Off
Set "_=0"
TaskList /FI "IMAGENAME eq dosbox.exe" 2>Nul|Find /I "dosbox.exe">Nul&&Set/A _+=1
TaskList /FI "IMAGENAME eq scva.exe" 2>Nul|Find /I "scva.exe">Nul&&Set/A _+=2

If %_% Equ 3 Exit/B

If %_% Equ 2 TaskKill /IM "scva.exe"&&Set/A _-=2

If %_% Equ 0 Start "" "DOSBox.exe"&&Set/A _+=1

If %_% Equ 1 Start "" /D "%~dp0.." /MIN "scva.exe"

Could you please comment as to whether my assessment is correct.

I would also be interested to know why you feel the need to recreate this in a different scripting language.

Compo
  • 36,585
  • 5
  • 27
  • 39