richtextbox for = i multiple function - vb.net

I am looking for the answer to my question, here I clearly explain the situation to you.
I have a richtextbox, and 10 lines included.
line1
line2
line3
line4
line5
..
line10
and i am doing this;
For i = 0 to richtextbox.Lines.Count = - 1
Button1_Click;
Dim getlist as Process = Process.Start("cmd", "commands" + richtextbox.Lines(i))
getlist.WaitForExit()
Next
I tried this but it didn't work;
Dim getlist as Process = Process.Start("cmd", "commands" + richtextbox.Lines(i))
Dim getlist2 as Process = Process.Start("cmd", "commands" + richtextbox.Lines(i + 1))
when I do this, it gets like;
first: richtextbox line 0 and line 1
and getlist starts line1 and getlist2 starts line2
I want it to be like;
getlist: line0
getlist2: line1
and who finishes earlier, the function starts to get new line;
for example:
getlist: line0-line2-line3-line5
getlist2: line1-line4-line6
how could I do this? thanks a lot for all answers!

In order to do this, you'll need to use some sort of threading-based solution to execute in parallel. Probably the most straightforward of these is to use Task-based asynchronous methods.
This would end up looking something like this:
Dim T1 = Task.Run(Sub()
Dim getlist as Process = Process.Start("cmd", "commands" & richtextbox.Lines(1))
getlist.WaitForExit()
End Sub)
Dim T2 = Task.Run(Sub()
Dim getlist as Process = Process.Start("cmd", "commands" & richtextbox.Lines(2))
getlist.WaitForExit()
End Sub)
Then, you would be able to use various approaches to wait for one or both tasks to finish. If you mark the containing routine as Async you could Await either T1 or T2. You can also Await Task.WhenAny to continue as soon as either one finishes.
I would strongly recommend reading the MSDN documentation on Task-based asynchrony. In particular, you should read "Implementing the Task-based Asynchronous Pattern", as the sections on Interleaving and Throttling are likely to be applicable to what you want to do. Unfortunately, the examples are all in C# in my copy of the online help, but the material should be straightforward to translate to VB.

If I understand your intention, this is the perfect application for threading. This works - I just wrote it, compiled it and ran it. To see it do some simple tasks in separate threads, running just 2 threads at a time until all commands have been executed, just enter valid shell commands into your richtextbox1. To test it, I used:
Echo A
Echo B
Echo C
Echo D
NOTES:
I appended a PAUSE into the CMD arguments, so you can see clearly what's happening.
Threading has a lot of nuances that I can't begin to get into here such as ApartmentState, but it's something that you'll want to educate yourself about.
I'm no guru, and I'm sure there are some more elegant ways to handle some of this 😄
Hope this helps!
Imports System.Threading
Public Class Form1
Dim Thread1 As Thread
Dim Thread2 As Thread
Dim Thread1cmd As String = ""
Dim Thread2cmd As String = ""
Dim Thread1Running As Boolean = False
Dim Thread2Running As Boolean = False
Dim LastCmd As Int32 = -1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
LastCmd = -1
While LastCmd < RichTextBox1.Lines.Count
If Thread1Running = False And (LastCmd + 1) < RichTextBox1.Lines.Count Then
LastCmd += 1
Thread1cmd = RichTextBox1.Lines(LastCmd)
output.Text += LastCmd.ToString + " Thread 1: " + Thread1cmd + vbCrLf
Thread1 = New Thread(AddressOf Thread1Helper)
Thread1.IsBackground = True
Thread1.Start()
End If
If Thread2Running = False And (LastCmd + 1) < RichTextBox1.Lines.Count Then
LastCmd += 1
Thread2cmd = RichTextBox1.Lines(LastCmd)
output.Text += LastCmd.ToString + " Thread 2: " + Thread2cmd + vbCrLf
Thread2 = New Thread(AddressOf Thread2Helper)
Thread2.IsBackground = True
Thread2.Start()
End If
'Note - there is debate around the DoEvents that follows, so experiment with it and see what works best for you
Application.DoEvents()
'the main thread now sleeps to give helper threads time to do some work:
System.Threading.Thread.Sleep(200)
End While
End Sub
Sub Thread1Helper()
Thread1Running = True
Dim p1 As System.Diagnostics.Process
Try
p1 = New System.Diagnostics.Process
Dim MyCMD As String = Environment.GetFolderPath(Environment.SpecialFolder.System) + "\cmd"
p1.StartInfo.FileName = MyCMD
p1.StartInfo.Arguments = " /c " + """" + Thread1cmd + "&&PAUSE" + """"
'MsgBox(p1.StartInfo.FileName.ToString)
p1.Start()
p1.WaitForExit()
p1.Close()
Catch ex As Exception
MsgBox(ex.ToString)
End Try
Thread1Running = False
End Sub
Sub Thread2Helper()
Thread2Running = True
Dim p2 As System.Diagnostics.Process
Try
p2 = New System.Diagnostics.Process
Dim MyCMD As String = Environment.GetFolderPath(Environment.SpecialFolder.System) + "\cmd"
p2.StartInfo.FileName = MyCMD
p2.StartInfo.Arguments = " /c " + """" + Thread2cmd + "&&PAUSE" + """"
'MsgBox(p2.StartInfo.FileName.ToString)
p2.Start()
p2.WaitForExit()
p2.Close()
Catch ex As Exception
MsgBox(ex.ToString)
End Try
Thread2Running = False
End Sub
End Class

Related

Multithreading and splitting the workload

So I created a spotify checker to check a list of accounts on their logins and current subscription, This works fine, but it's only running on one thread and that in my opinion is really slow. So I started searching around for multithreading (I am pretty new to vb.net and am trying to learn this way.) But everything I threw at it would just run all threads seperately on the same accounts without any difference in results, just that they were printed out multiple times.
The code for the sub Login:
Public Sub Login()
Dim index As Integer = 0
While index < Combos.Count
Dim str() As String = Combos(index).Split(":")
Using req As New HttpRequest
req.UserAgent = Http.ChromeUserAgent
req.Cookies = New CookieDictionary()
req.Proxy = Nothing
req.IgnoreProtocolErrors = True
req.Get("https://accounts.spotify.com/en-US/login?continue=https:%2F%2Fwww.spotify.com%2Fus%2Faccount%2Foverview%2F")
Dim token As String = req.Cookies.ToString
Dim csrf As String = Regex.Match(token, "csrf_token=(\S+)").Groups(1).ToString
req.Referer = "https://accounts.spotify.com/en-US/login?continue=https:%2F%2Fwww.spotify.com%2Fus%2Faccount%2Foverview%2F"
req.AddHeader("Cookie", "csrf_token=" + csrf + "; __bon=MHwwfDQ1MzY4Nzk4M3wxOTA1NDg5NTI4NnwxfDF8MXwx; fb_continue=https%3A%2F%2Fwww.spotify.com%2Fus%2Faccount%2Foverview%2F; remember=false")
req.AddParam("remember", "false")
req.AddParam("username", str(0))
req.AddParam("password", str(1))
req.AddParam("captcha_token", "")
req.AddParam("csrf_token", csrf)
Dim respo As String = req.Post("https://accounts.spotify.com/api/login").ToString
If respo.Contains("displayName") Then
Dim IT As New ListViewItem
IT.Text = str(0)
IT.SubItems.Add(str(1))
Dim html As String = req.Post("https://spotify.com/account/subscription/").ToString
Dim Info As Match = Regex.Match(html, "<h3.*>(.*)<\/h3>")
Dim Type As String = Info.Groups(1).Value
If Type.Contains("Spotify Premium") Then
IT.SubItems.Add("Spotify Premium")
ListView1.Items.Add(IT)
Label3.Text += 1
Label1.Text += 1
ElseIf Type.Contains("Premium for Family") Then
IT.SubItems.Add("Spotify Premium for Family")
ListView1.Items.Add(IT)
Label3.Text += 1
Label1.Text += 1
Else
If StrafeCheckBox1.Checked = False Then
Label2.Text += 1
Else
IT.SubItems.Add("Free")
ListView1.Items.Add(IT)
Label1.Text += 1
End If
End If
Else
Label2.Text += 1
End If
End Using
index += 1
StrafeProgressBar1.Value = index
If index = Combos.Count Then
MsgBox("Done, successfull logins: " + Label1.Text)
End If
End While
End Sub
Code for the start button:
Private Sub LoginBTN_Click(sender As Object, e As EventArgs) Handles StartBTN.Click
Dim IH As New Thread(AddressOf Login) : IH.Start()
StrafeProgressBar1.Maximum = Combos.Count
End Sub
So what I basically want to know, is how I get the threads to split the
workload evenly. and finish the job a lot quicker.
All help is appreciated.

Process.Start() with "manage-bde.exe" crashing in VB.NET

I'm trying to start manage-bde.exe as a new process in VB.net but when it tries to start the proc, Bitlocker crashes. Could anyone please tell me what I'm doing wrong here? This code was converted from C# where it works all day long....
Code:
Private Sub btnLock_Click(sender As Object, e As EventArgs) Handles btnLock.Click
Dim drvSelected As String = cmbDriveSelect.SelectedValue.ToString()
Dim sysDirWithBDE As String = Environment.SystemDirectory + "\manage-bde.exe"
Dim lockStatus As String = String.Empty
' This is the code for the base process
Dim myProcess As New Process()
' Start a new instance of this program
Dim myProcessStartInfo As New ProcessStartInfo(sysDirWithBDE, " -lock " + drvSelected.Remove(2))
'Set Use Shell to false so as to redirect process run info to application
myProcessStartInfo.UseShellExecute = False
myProcessStartInfo.RedirectStandardOutput = True
myProcess.StartInfo = myProcessStartInfo
Try
myProcess.Start()
lblDriveLockMsg.Show()
Catch err As Exception
lblDriveLockMsg.Text = err.Message
End Try
'Read the standard output of the process.
lockStatus = myProcess.StandardOutput.ReadToEnd()
If lockStatus.Contains("code 0x80070057") Then
lblDriveLockMsg.Text = "Drive selected is not Bit Locker encrypted"
ElseIf lockStatus.Contains("code 0x80070005") Then
lblDriveLockMsg.Text = "Drive selected is in use by an application on your machine, force dismounting might result in data loss, please check and close any applications using the drive"
Else
lblDriveLockMsg.Text = lockStatus
End If
myProcess.WaitForExit()
myProcess.Close()
End Sub

More Efficient Way To Wait/Listen for a Process

I have a tool that I have been using but it is hit or miss. It uses sendkeys to open a pdf from another application. I then check to see if the pdf opened, close that pdf by killing the process, then use sendkeys again to go to the next document. However, I have found that if there is any lag time between network and/or filesize, the program doesn't detect the process and the program stops functioning. Is there a better way to listen to a process?
Sub ProcessPDF()
Dim z As Integer = Next1
AppActivate("Hyperspace")
For i = 1 To z
SendKeys.SendWait("{ENTER}")
p = Process.GetProcessesByName("Acrobat")
If p.Count > 0 Then
p(0).CloseMainWindow()
SendKeys.SendWait("{LEFT}")
SendKeys.SendWait("^Q")
SendKeys.SendWait("{DOWN}")
Else
label2.Text = "An error has occurred! Please try again."
MsgBox("An error has occurred! Please try again.")
End If
Next1 = Next1 - 1
label2.Text = Next1 & " PDFs Left!"
Next
End Sub
Way 1:
wait:
For Each p In Process.GetProcesses
If p.ProcessName = ("Acrobat") Then
Threading.Thread.Sleep(1000)
GoTo wait
End If
Next
Way2:
Private Function Run(ByVal process As String, ByVal parameters As String) As String
Dim psi As ProcessStartInfo = New ProcessStartInfo(process)
psi.Arguments = "your commands"
psi.RedirectStandardError = True
psi.UseShellExecute = False
Dim output As String = String.Empty
Dim proc As Process = System.Diagnostics.Process.Start(psi)
proc.WaitForExit()
Dim outputStream As StreamReader = proc.StandardError
output = outputStream.ReadToEnd
proc.Close()
Return output
End Function
Force Kill:
waitkill:
For Each p In Process.GetProcesses
If p.ProcessName = ("Acrobat") Then
p.Kill()
GoTo waitkill
End If
Next

Realtime console redirection issue

First of all, I did spend quite some time trying to find an answer to my issue but so far, nothing.
Here is the issue.
I have to run a cli command with arguments and redirect the output (REALTIME) to a textbox.
The command will look like this:
smcli - n name -f "script.scr"
Since smcli is not in the system PATH variable, I first need to go to the right Dir
So, I end up running the full command that looks like this:
cmd /c cd "c:\Program Files(x86)\bla\" && smcli - n name -f "script.scr"
I'll put the code in one sec but basically, the thing is working just fine, I get to the correct directory, run the command, it runs the script, all good.
I tried to redirect the output to a different form but then it doen't work anymore at all; anyway, that would be the bonus question.
The thing is though, when the script runs, it does say step by step what it is doing and sends that info to the output (i.e. restoring the name, restoring the disk config, ...)
As I said, I do get all those outputs....once EVERYTHING is completed (i.e. after 5 minutes of apparent freeze).
NOT redirecting the output to the textbox (i.e. leaving the console window open), I get the output real time.
So here is the code now (there is a bit of it, sorry):
Private Sub ReadMDcfgToolStripButton_Click(sender As Object, e As EventArgs) Handles ReadMDcfgToolStripButton.Click
Dim exitcode As Int32
smcli = Environment.GetEnvironmentVariable("ProgramFiles") & "\Dell\MD Storage Manager\client\" 'SMcli.exe"
Dim gotosmclidir As String = "cd """ & smcli & """"
Dim smclicommand As String
smclicommand = "smcli -n " & mdname & " -c ""save storagearray configuration file=\""" & saveFileDialog2.FileName & "\"" allconfig"";"
cmd = gotosmclidir & " && " & smclicommand
exitcode = RunCommandCom(cmd, "", False)
End Sub
Private Function RunCommandCom(command As String, arguments As String, permanent As Boolean) As Int32
' Usage:
'RunCommandCom("DIR", "/W", true)
'For the multiple command on one line the key are the & | && and || command connectors
'•A & B -> execute command A, then execute command B.
'•A | B -> execute command A, and redirect all it's output into the input of command B.
'•A && B -> execute command A, evaluate the errorlevel after running Command A, and if the exit code (errorlevel) is 0, only then execute command B.
'•A || B -> execute Command A, evalutate the exit code of this command and if it's anything but 0, only then execute command B.
TextBox1.Text = "Communication in progress..." & vbCrLf
exitcodelbl.Text = ""
CmdCloseBtn.Enabled = False
ToolStrip1.Enabled = False
CmdOutputPanel.Visible = True
Dim p As Process = New Process()
Dim pi As ProcessStartInfo = New ProcessStartInfo()
pi.FileName = "cmd.exe"
pi.Arguments = " " + If(permanent = True, "/K", "/C") + " " + command + " " + arguments
MsgBox(pi.Arguments)
pi.CreateNoWindow = True
pi.UseShellExecute = False
pi.RedirectStandardOutput = True
pi.RedirectStandardError = True
pi.CreateNoWindow = True
p.StartInfo = pi
AddHandler p.OutputDataReceived, AddressOf GotData
p.Start()
p.BeginOutputReadLine()
Do Until p.HasExited
Loop
exitcodelbl.Text = p.ExitCode
Select Case p.ExitCode
Case 0
exitcodelbl.Text += " - Command completed successfully."
Case 1
exitcodelbl.Text += " - Could not communicate with the Array."
Case 9
exitcodelbl.Text += " - Could not communicate with the Array."
Case 14
exitcodelbl.Text += " - Could not communicate with the Array."
Case Else
exitcodelbl.Text += " - Unknown code."
End Select
Return p.ExitCode
End Function
Sub GotData(ByVal sender As Object, ByVal e As DataReceivedEventArgs)
UpdateTextBox(e.Data)
End Sub
Private Delegate Sub UpdateTextBoxDelegate(ByVal Text As String)
Private Sub UpdateTextBox(ByVal Tex As String)
If Me.InvokeRequired Then
Dim del As New UpdateTextBoxDelegate(AddressOf UpdateTextBox)
Dim args As Object() = {Tex}
Me.Invoke(del, args)
Else
TextBox1.Text &= Tex & Environment.NewLine
End If
End Sub
Apart from the command itself, everything else is comming from researches and they are just put together, the way to run the command on one hand and the redirection on the other hand.
I believe the issue is with my command (looks like that part is VERY sensible).
Either I can have it done a different way (again, it works but not real time) or I missed something trivial...?
Thanks for your help.
Following tinstaafl here is the updated code:
Private Sub MainForm_Shown(sender As Object, e As EventArgs) Handles MyBase.Shown
copyrightlbl.Focus()
wait(1000)
Await RunCommandCom("", "192.168.219.152", False) '172.16.1.55
CmdCloseBtn.Enabled = True
End Sub
Private Async Function RunCommandCom(command As String, arguments As String, permanent As Boolean) As Task(Of Int32)
TextBox1.Text = "Communication in progress..." & vbCrLf
exitcodelbl.Text = ""
CmdCloseBtn.Enabled = False
ToolStrip1.Enabled = False
CmdOutputPanel.Visible = True
Dim p As Process = New Process()
With p.StartInfo
.WorkingDirectory = Environment.GetEnvironmentVariable("ProgramFiles") & "\Dell\MD Storage Manager\client\" 'Directory for SMcli.exe"
.FileName = "ping.exe"
.Arguments = command + " " + arguments
.CreateNoWindow = True
.UseShellExecute = False
.RedirectStandardOutput = True
.RedirectStandardError = True
End With
p.Start()
Do Until p.HasExited
TextBox1.Text &= Await p.StandardOutput.ReadLineAsync
Loop
exitcodelbl.Text = p.ExitCode
Return p.ExitCode
End Function
Instead of using a delegate try reading the output directly to the textbox. The StandardOutput property of the Process is a stream that you can use the ReadLineAsync method to get the output. Something like this should work:
pi.CreateNoWindow = True
pi.UseShellExecute = False
pi.RedirectStandardOutput = True
pi.RedirectStandardError = True
p.StartInfo = pi
p.Start()
Do Until p.HasExited
TextBox1.Text &= Await p.StandardOutput.ReadLineAsync
Loop
Intellisense will prompt you to make the sub routine Async, but with that you should get the output you want.
Private Async Function RunCommandCom(command As String, arguments As String, permanent As Boolean) As Task(Of Int32)
Await RunCommandCom("", "192.168.219.152", False)

cmd process not exiting

I was running the following code to execute commands from vb.net app.
Dim CMDServer As Diagnostics.ProcessStartInfo
Dim CMDReply As Diagnostics.Process
CMDServer = New Diagnostics.ProcessStartInfo
CMDServer.WorkingDirectory = "C:/"
CMDServer.FileName = "cmd.exe"
CMDServer.UseShellExecute = False
CMDServer.RedirectStandardOutput = True
CMDServer.RedirectStandardError = True
CMDServer.CreateNoWindow = True
CMDServer.Arguments = "/C " + command
CMDReply = Process.Start(CMDServer)
MsgBox("START")
Dim Reply As String = ""
If Not CMDReply.HasExited Then
CMDReply.WaitForExit()
End If
MsgBox("EXIT")
Try
Dim ext = CMDReply.ExitCode
Reply = CMDReply.StandardOutput.ReadToEnd()
MsgBox(ext.ToString + " " + Reply)
Catch ex As Exception
MsgBox(ex.ToString)
End Try
it works fine for almost all commands, but when the command="help" the program stucks on CMDReply.WaitForExit(). Can anyone explain what may be the problem here?
Standard deadlock. Read the output first and then wait for exit. The
program cannot exit until you've read all of its output. The code you
have can only work if there's little output that fits the buffer.
From Hans Passant's comment