2

My batch file:

SET username=%1
SET password=%2

net use "\\gessel\toys\name" %password% /user:shops\%username%
ECHO.%ERRORLEVEL%
:copy
Xcopy "\\gessel\toys\name\babytoys" "%appdata%\shops" /S /E
ECHO.%ERRORLEVEL%

IF ERRORLEVEL 0 goto disconnect
goto end
:disconnect 
net use "\\gessel\toys\name\babytoys" /delete
goto end
:end
EXIT /B %ERRORLEVEL%

I have called above batch file from VBA and the code as follows:

call Shell(Environ$("COMSPEC") & " /c " & path & username & password, vbHide)

The above code is works fine. But I need to validate whether the files are copied or not in the VBA. Suppose the customer entered his username and password wrongly then he won't get the toys info. Then I have to display a message box that display message as "entered information wrong". So for that I have tried the code like this:

sub submit_click

    Dim as error as integer
    error = Shell(Environ$("COMSPEC") & " /c " & path & username & password, vbHide)
    if error <> 0
        MsgBox "Provided info wrong", vbOKOnly, "Failure"
    end if
end sub

But the above code does not work. It always returns the value even the username and password is correct. But if I run the batch file it correctly returns value such as for correct details 0 and for wrong data is 2 or 4. Please anyone help me to capture error code from batch file and to pass it into VBA.

Martin Prikryl
  • 188,800
  • 56
  • 490
  • 992
viji
  • 119
  • 2
  • 3
  • 12

1 Answers1

5

The value of ERRORLEVEL variable changes with each command execution (more or less). So as the code in your batch file is executing, each command generates a change. You need to store the value for later processing or, in your case, exit with the adecuated value in each of the steps:

SET "username=%~1"
SET "password=%~2"

rem This will be tested for a errorlevel value of 1 or greater. In this case, 
rem no further processing will be done if errors found, so we return our own 
rem value to the calling process

net use "\\gessel\toys\name" %password% /user:shops\%username% 
if errorlevel 1 exit /b 100

rem We are connected, and will disconnect no matter if xcopy worked or failed
rem So, the result of the command will be stored to later return the adecuate value

Xcopy "\\gessel\toys\name\babytoys" "%appdata%\shops" /S /E
set "exitCode=%errorlevel%"

net use "\\gessel\toys\name\babytoys" /delete

EXIT /B %exitCode%

Now, in the vba code the error variable can be tested for value 100 (what we returned from errors in net use) or for any of the values returned from xcopy.

Now that we have a working batch file, let's to to Excel.

NO, Shell function in VBA can not do what you are asking. The return value of Shell is the id of the running process. Shell do not wait for the process to end, so, it can not return its exit code.

BUT, the WshShell object can do what you need.

Dim oSHELL, batchFile, user, password, exitCode
    Set oSHELL = VBA.CreateObject("WScript.Shell")
    batchFile="myBatchFile.cmd"
    user="myUserName"
    password="this is my password"

    ' Quote strings to avoid problems with spaces
    ' The arguments are WhatToRun, WindowStyle (0=hide), WaitForProcessToEnd
    exitCode = oSHELL.Run(""""+batchFile+""" """+user+""" """+password+"""", 0, True)
MC ND
  • 69,615
  • 8
  • 84
  • 126
  • Thanks. I have modified the code as your suggestion. but i am getting another issue. if i run the batch file separately it looks good. but from the code it always copying the files even if i provide data wrongly. could you plz help on this ? – viji Mar 19 '14 at 12:21
  • @viji, i've being testing and i was not able to execute a `net use` command, with invalid data, without getting an errorlevel set. With errorlevel set, the batch file exits on the line after the net use and no file is copied. Can you try in your system to execute the command with invalid data from command line and see if it sets the errorlevel and which value it sets? – MC ND Mar 19 '14 at 13:07
  • I have tried out. it looks good. but this line is taking much time to execute "exitCode = oSHELL.Run(""""+batchFile+""" """+user+""" """+password+"""", 0, True)" i mean it will not return back to the application. is it possible to set wait or sleep time until batch file execution ? – viji Mar 19 '14 at 13:23
  • but if i run seperately batch file it takes juz 2 or 3 seconds. do u have any idea ? – viji Mar 19 '14 at 13:31
  • 1
    @viji, the last parameter in the function call (`True`) indicates that the call should not return until the batch file finishes. If it does not wait for the called process to end, then there is no access to the exit code (it has not finished). What is exactly the behaviour you think it should have? – MC ND Mar 19 '14 at 13:32
  • i have awaited more than 30 minutes to exit the process. but still the batch file is executing the process not at all ends. so is there any to stop the process by providing the time limit ? if i change the value 0 to 1 in the function call then it executes soon and the process ends within 3 secs. but my aim is to hide the batch file execution from the user. so i have changed it(changed to 0) again, then it takes around 1 hour to stop the process. – viji Mar 19 '14 at 13:43
  • @viji, i can not reproduce the behaviour you have indicated. But net commands can ask for confirmation in some operations. Maybe you have the net command waiting for input. Try `/Y` or `/N` switches in the command to answer Yes or No to whatever it could be asking and see if it waits or not – MC ND Mar 19 '14 at 17:01
  • Thanks for your quick help. is there any way to capture error from batch file to vba other than the "Run" func ? – viji Mar 20 '14 at 09:30
  • @viji, you can use the `Exec` method of the `WshShell` object the get the output of the command, or you can use a temporary file, or you can use the API ([see here](http://stackoverflow.com/a/1439241/2861476)) – MC ND Mar 20 '14 at 09:44