show a trackbar or image while shell() is running a cmd.exe instruction - vb.net

I'm trying to do a simple windows form application in visual basic that change the attributes of all the files in a drive using shell().
It works but since sometimes there are a lot of files, the applications looks like it freeze (because I'm using the "wait" argument as true.
So I'm looking for a way to show an "load" gif while the cmd is doing his thing, I found and example in msdn for a "wait until process finish" using interaction.Start (http://msdn.microsoft.com/en-us/library/microsoft.visualbasic.interaction.shell(v=vs.110).aspx) I tried to mix shell with that example but I can't get it to run ok.
This is my code so far.
pic_working.Visible = True
myDrive = "F:\"
Dim procID As Integer
Dim newProc As Diagnostics.Process
newProc = Diagnostics.Process.GetProcessById(Shell("cmd.exe /C attrib -r " + myDrive + "*.* /s /d", AppWinStyle.NormalFocus, False))
procID = newProc.Id
Dim procEC As Integer = -1
If newProc.HasExited Then
procEC = newProc.ExitCode
End If
MsgBox("Process with ID " & CStr(procID) & " terminated with exit code " & CStr(procEC))
myDrive =""
pic_working.Visible = False
It works...kind of... when I set the wait argument for shell() to "true" it take like 30 seconds to complete the task (in my test drive), but with it to false it just skips everything and my pic_Working is never showed.
Can you give me a hint... it's possible to do this in this way, or I have to do the long way (using File.SetAttributes and parsing one file at the time?
Thanks!

Disclaimer: C++ guy here.
Set Wait to False. If Shell tells you the program is still running, display your image, start a Timer, Use the Win32 API OpenProcess with the PID returned by Shell and save the HANDLE, and return. On each Timer Tick, use the Win32 API WaitForSingleObject with the HANDLE and with a timout equal to 0. If the process handle is successfully signaled, then the task is terminated.
EDIT
How to know when a process is terminated, when you have successfully got an HANDLE to that process with OpenProcess:
HANDLE hProcess;
[...]
DWORD dwRet = WaitForSingleObject( hProcess, 0 );
if ( dwRet == WAIT_OBJECT_0 ) {
// Process is terminated. Don't forget to close the handle
CloseHandle( hProcess );
} else if ( dwRet == WAIT_TIMEOUT ) {
// Process NOT terminanted, wait next Timer Tick
} else {
// Error Occurred
DWORD dwLE = GetLastError();
}
Using the Win32 HANDLE type in C#/VB: use IntPtr

Related

How to run WSL programs within AutoIt?

I'm trying to run a linux console application using AutoIt.
So far I was successful in generating a batch file with the following command:
wsl /home/ggeorgiev/DD/myprogram --json_file /mnt/c/Users/ggeorgiev/my_input.json
This batch runs successfully from cmd, powershell and also when I just double click on it in the explorer. So, I'm thinking that part is okay.
In AutoIt, I'm trying to run the same batch file ("JBDD_start.bat") using the following function:
Func RunJBDD()
Local $iPID = Run("cmd.exe " & "JBDD_start.bat", #WorkingDir, #SW_HIDE, BitOR($STDERR_CHILD, $STDOUT_CHILD,$RUN_CREATE_NEW_CONSOLE ))
Local $sOutput = ""
While 1
$sOutput &= StdoutRead($iPID)
If #error Then ; Exit the loop if the process closes or StdoutRead returns an error.
ExitLoop
EndIf
MsgBox($MB_SYSTEMMODAL, "Stdout Read:", $sOutput)
WEnd
$sOutput = ''
While 1
$sOutput &= StderrRead($iPID)
If #error Then ; Exit the loop if the process closes or StderrRead returns an error.
ExitLoop
EndIf
MsgBox($MB_SYSTEMMODAL, "Stderr Read:", $sOutput)
WEnd
EndFunc
It doesn't show anything in the StdErr nor in StdOut message boxes.
Any suggestions on what may have gone wrong or how to find what happens "behind the scenes" are highly appreciated.
Try this, maybe it helps to get your output.
ConsoleWrite( _getDOSOutput('ping 4.2.2.2') & #CRLF)
Func _getDOSOutput($command)
Local $text = '', $Pid = Run('"' & #ComSpec & '" /c ' & $command, '', #SW_HIDE, 2 + 4)
While 1
$text &= StdoutRead($Pid, False, False)
If #error Then ExitLoop
Sleep(10)
WEnd
Return $text
EndFunc ;==>_getDOSOutput
I'm not familiar with AutoIt, but I'm going to take an educated guess here. If I'm wrong, at least it might help someone else.
I notice that AutoIt comes with both 32-bit and 64-bit executables. Make sure you are either:
Using the 64-bit version to execute your batch file
Or, if you really do need to run the 32-bit version of AutoIt, call C:\Windows\Sysnative\wsl.exe

run external program and exit from calling program

n the closing procedure of a program (just before running Application.exit) I need to run an external program to pass a parameter and exit the calling program.
The program called (FilmDB_Update.exe) has the task of overwriting the main program or a dll library.
I tried to use the "process.start" technique, but apparently, the calling program remains in use and does not allow me to overwrite it.
This is the code that I write:
Private Sub AggiornaPgm()
Dim ws_file As String = "FilmDB_Update.exe"
Dim ws_proc_param As String = """" + ws_working_path + """ " + ws_temp_path
Dim ws_fullPath As String = Path.Combine(ws_temp_path, ws_file)
If File.Exists(ws_fullPath) Then
File.Copy(ws_fullPath, ws_file, True)
End If
Dim proc As New System.Diagnostics.Process()
proc = Process.Start(ws_file, ws_proc_param)
End Sub
I wanted to try using the shell command, but I can not pass the parameters to the called program.
Does any of you have any other ideas about it?
Thank you
Marcello
As Ahmed suggested, I added the test for the calling process to the program called.
p = Process.GetProcessesByName(ws_calling_pgm)
While p.Count > 0
Threading.Thread.Sleep(3000)
p = Process.GetProcessesByName(ws_calling_pgm)
End While
p = Nothing
When I exit the While loop, the calling process is terminated. I do not understand why, despite the process no longer exists, the main program is still in use.

There is no Wait Method associated with Application in VisualBasic Word

I have VBA code to run a particular code and I am trying to pause the next execution by giving it a wait time of 3 seconds using the following line:
Application.Wait (Now + TimeValue("00:00:03"))
But I get the following error:
Error: Method or data variable not found
It is best to use External Library references (Early Binding) while developing your code. Early Binding has the advantages of both intellisense and Help documentation. A major disadvantage of Early Binding is that it requires the reference to be updated if a different version of the library is installed. This is way it is best to remove the external references and convert code to Late Binding before distributing it.
Late binding uses CreateObject to import and instantiate a class object.
CreateObject("Excel.Application").Wait (Now + TimeValue("00:00:05"))
Alternatively, you could reference the WinApi Sleep function.
Private Declare Sub Sleep Lib "kernel32.dll" (ByVal dwMilliseconds As Long)
Usage:
Sleep 3000 '3000 Milliseconds = 3 second delay
I use this function in all of my macros that require a paste operation (sometimes paste is too quick and the pc can't copy the selection in time resulting in an error):
Function Wait(ByVal Seconds As Single)
Dim CurrentTimer As Variant
CurrentTimer = Timer
Do While Timer < CurrentTimer + Seconds
Loop
End Function
Then apply the following right before any "Selection.Paste" or "Selection.PasteSpecial":
Application.Excel.Wait (Now + TimeValue("00:00:01"))
You may also have to enable the "ExcelPlugInShell 1.0 Type Library" found in Tools > References to get this to function properly as this uses language not available in MS Word by default.
I tried Excel.Application.Wait(Now + TimeValue("00:00:03")) and it worked like a charm!
This works for me:
Set wsh = VBA.CreateObject("WScript.Shell")
Dim waitOnReturn As Boolean: waitOnReturn = True
Dim windowStyle As Integer: windowStyle = 0
Dim errorCode As Integer
errorCode = wsh.Run("timeout 5", windowStyle, waitOnReturn)
this code allows to run cmd command and wait until execution is finished, in this particular case I am running command "timeout 5" which simly wait 5 seconds.
I've found documentation here

Console App / Task Scheduler

I have a console app written in VB Net that works perfectly. Now I want to run it using task scheduler. The problem is that the app has a console.readline command at the very end that keeps the console window open until the user hits enter. Is there a way to test whether the app is running in a session or not?
If I knew that the app was not tied to a desktop console, I would not write the comments to the console and I'd bypass the final console.readline command.
You should add an argument to your task to indicate it is unattended. For example, pass /u in your scheduled task. Check for /u in your program to determine if it should skip the console.readline.
excerpt from msdn forum
Dim args() As String = Environment.GetCommandLineArgs()
' args(0) = Full path of executing program with program name
' args(1) = First switch in command - /u
if args(1) = "/u" then ....
Or you can change the signature of your Main() to Public Sub Main(ByVal args() As String) and you won't need to use Dim args() As String = Environment.GetCommandLineArgs()

pause/ wait for *.bat to finish VB.net

hi i need to pause/ wait the bellow VB program between the arorasTEMP.bat and the "Label2.Text = "Appending for AutoCAD version A..." as it happens the bat is appending before its temp copy is made
Dim RetBat1
RetBat1 = Shell("C:\VTS\arorasTEMP.bat", 1)
Label2.Text = "Appending for AutoCAD version A..."
'Appending the acad2011.lsp
If System.IO.File.Exists(FILE_NAME1) = True Then
Dim objWriter As New System.IO.StreamWriter(FILE_NAME1, True)
objWriter.WriteLine(arorasKEY)
objWriter.Close()
End If
can anyone give example?
Shell is a VB6 command, it's not the ideal way to launch processes.
The proper way in .NET to invoke a process and wait for it is:
Dim aroras as Process = Process.Start("C:\VTS\arorasTEMP.bat")
aroras.WaitForExit()
' error code is available in aroras.ExitCode, if you need it
You can also forcibly kill it if it takes too long:
If Not aroras.WaitForExit(300) Then
aroras.Kill()
End If
(where 300 is the time in milliseconds to wait)
you can tell the shell to wait for the process to be done before executing anything else:
RetBat1 = Shell("C:\VTS\arorasTEMP.bat", ,True)
And even give a timeout that stops the execution if it takes too long, in this case 6 seconds:
RetBat1 = Shell("C:\VTS\arorasTEMP.bat", , True, 6000)
More info about the Shell function: http://msdn.microsoft.com/en-us/library/xe736fyk(VS.80).aspx