Opening up process and grabbing window title. Where did I go wrong? - vb.net

In my application I allow for the users to add a program from a open file dialog, and it then adds the item to a listview and saves the items location into the tag. So what I am trying to do is when the program in the listview is selected and the button is pressed, it starts a timer and this timer checks to see if the process is running, and if it isn't launches the process, and once the process is launched it gets the window title of the process and sends it to a textbox on another form.
EDIT:
The question is if anyone can see why it is not working, by this I mean starting the process, then when it's started closing the form and adding the process window title to a textbox on another form.
I have tried to get it working but I can't. I know that the process name it is getting is right I think my problem is to do with my for loop. Basically it isn't doing anything visible right now.
I feel like I am very close with my code and im hoping it just needs a couple minor tweaks. Any help would be appreciated. Sorry if my coding practices aren't that great, im pretty new to this.
**EDIT:I found solution. I added code to the button that enables my timer to execute the process. Also another problem was indeed the way it read the file, I had to use the replace function to remove the ".exe" from the filepath code.
EDIT 2 : A better solution has been posted by Mark Hall. I am now using his code as it has less chance for error.
Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
Dim s As String = ListView1.SelectedItems(0).Tag
Dim myFile As String = Path.GetFileName(s)
Dim mu As String = myFile.Replace(".exe", "").Trim()
Dim f As Process
Dim p As Process() = Process.GetProcessesByName(mu)
For Each f In p
If p.Length > 0 Then
For i As Integer = 0 To p.Length - 1
ProcessID = (p(i).Id)
AutoMain.Name.Text = f.MainWindowTitle
Timer1.Enabled = False
Me.Close()
Next
Else
ProcessID = 0
End If
If ProcessID = 0 Then
Process.Start(mu)
End If
Next
End Sub

What is happening is that you are looking for a Process that matches your parameters before you enter your For Each loop the Process array is empty so it never enters it, therefore you never start your process.
This is a very quick example that works:
Private Sub Timer1_Tick(sender As System.Object, e As System.EventArgs) Handles Timer1.Tick
Dim s As String = ListView1.SelectedItems(0).Tag.ToString
Dim myFile As String = Path.GetFileName(s)
Dim p As Process() = Process.GetProcessesByName(Path.ChangeExtension(myFile, Nothing))
Static started As Boolean
If p.Count > 0 Or started Then
If p.Length > 0 Then
For i As Integer = 0 To p.Length - 1
ProcessId = (p(0).Id)
AutoMain.Name.Text = p(0).MainWindowTitle
Timer1.Enabled = False
started = False
Timer1.Stop()
Me.Close()
Next
Else
ProcessId = 0
End If
Else
started = True
Process.Start(myFile)
End If
End Sub

Related

Why is the process id not found in GetProcesses()

I am starting a PDF, and I get a process.
The PDF is shown in a Chrome window.
Then I try to find this process among the processes, but it is not there.
I have even tried adding some time to wait before calling GetProcesses(), but that wouldn't change anything.
What am I missing?
Private Sub btnTest_Click(sender As Object, e As EventArgs) Handles btnTest.Click
Dim sPath As String = "d:\test.pdf"
Dim nProc As Process = System.Diagnostics.Process.Start(sPath)
Dim iProcID As Integer = nProc.Id
Dim allProcesses() As Process = System.Diagnostics.Process.GetProcesses
For Each nProcess As Process In allProcesses
If nProcess.Id = iProcID Then
Stop 'found :-)
End If
Next
End Sub

VB.net ContinueWith

I have this code which loops through all my accounts in my list and then does something to the accounts using tasks for each account as a way to speed up the process. Each time the program completes this action, I want the user interface to update the progress bar. I was using Invoke before but it isn't the best option and I couldn't get it working. Now I know this can be done using a background worker but this isn't the best way of making your application multithreaded so I used this. And instead of invoking I heard about ContinueWith but I can't seem to get it working and I get no error message just a red underline.
Code:
progressBar.Value = 0
Dim tasks As New List(Of Task)()
For Each account In combos
Dim t As Task = Task.Run(Sub()
While checked = False
If proxies.Count = 0 Then
Exit Sub
'Also can't think of a good way to stop searching through accounts when there are no proxies left in my queue.
End If
Dim proxy As New WebProxy(proxies(0))
proxies.TryDequeue(0)
'Do something
End While
checkedAmount += 1
Dim progress As Integer = ((checkedAmount / combos.Count) * 100)
Task.ContinueWith(progressBar.Value = progress, TaskScheduler.FromCurrentSynchronizationContext()) 'Error here
End Sub)
tasks.Add(t)
Next
Task.WaitAll(tasks.ToArray())
I get no error code as shown here:
I have also tried putting a sub after and stuff but that lead to nothing.
Thanks for any help in advance.
Update tried with invoke:
Private Delegate Sub UpdateProgressBarDelegate(ByVal progressBarUpdate As ProgressBar, ByVal value As Integer)
Dim checkedAmount As Integer = 0
Dim checked As Boolean = False
Private Sub startBtn_Click(sender As Object, e As EventArgs) Handles startBtn.Click
progressBar.Value = 0
Dim tasks As New List(Of Task)()
For Each account In combos
Dim t As Task = Task.Run(Sub()
While checked = False
proxies.TryDequeue(0)
'do stuff
End While
checkedAmount += 1
Dim progress As Integer = ((checkedAmount / combos.Count) * 100)
If Me.InvokeRequired = True Then
Me.Invoke(New UpdateProgressBarDelegate(AddressOf UpdateProgressBar), progressBar, progress)
Else
UpdateProgressBar(progressBar, progress)
End If
'Task.ContinueWith(progressBar.Value = progress, TaskScheduler.FromCurrentSynchronizationContext())
End Sub)
tasks.Add(t)
Next
Task.WaitAll(tasks.ToArray())
End Sub
Private Sub UpdateProgressBar(ByVal ProgressBarUpdate As ProgressBar, progress As Integer)
progressBar.Value = progress
End Sub
Still doesn't work not sure why?
Now I know this can be done using a background worker but this isn't the best way of making your application multithreaded
Sort of.
BackgroundWorker is a poor way to run many different Tasks individually. No one wants to deal with a separate BackgroundWorker component for each Task. But one BackgroundWorker is a great way to spawn just one extra thread to manage all your other Tasks and update the progress bar. It's an easy solution here.
Either way, the one thing you'll want to do for sure is move the code to update the ProgressBar out of the individual Tasks. Having that inside a Tasks violates separation of concerns1. Once you do that, you'll also need to change the call to WaitAll() to use WaitAny() in a loop that knows how many tasks you have, so you can still update the ProgressBar as each Task finishes. This will likley have the side effect of fixing your current issue, as well.
Private Async Sub startBtn_Click(sender As Object, e As EventArgs) Handles startBtn.Click
Dim tasks As New List(Of Task)()
For Each account In combos
Dim t As Task = Task.Run(Sub()
While Not checked
proxies.TryDequeue(0)
'do stuff
End While
End Sub)
tasks.Add(t)
Next
progressBar.Value = 0
For i As Integer = 1 To tasks.Count
Dim t = Await Task.WhenAny(tasks)
tasks.Remove(t)
progressBar.Value = (i / combos.Count) * 100
Next i
End Sub
1 The problem here illustrates one reason we care about separation of concerns at all. Once I fix this, the code becomes much simpler and the frustrating errors just go away.
The above waitany is unnecessary.
I have found that you might as well put your progress bar code directly into the task run sub:
Dim ProgressBarSync As New Object
Dim tasks As New List(Of Task)()
For Each account In combos
Dim t As Task = Task.Run(
Sub()
'do stuff
SyncLock ProgressBarSync
ProgressBar.Increment(1)
End SyncLock
End Sub)
tasks.Add(t)
Next

Open multiple URLs successively in WebBrowser control in VB.NET

I'm trying to make a "rotator" on a form that cycles through a series of urls and displays the url in the WebBrowser control. The following code displays my form, but the form remains white/blank and then the last url in the array appears after a while. When I put a MessageBox in-between each url, to create a stop, it works and each url appears. I've tried putting a Sleep in place of the MessageBox, but that didn't work. I've also tried increasing the Sleep time, but that didn't work either. How can I make it work correctly?
Sub Rotate()
Dim Urls() As String = {"www.stackoverflow.com", "www.google.com", "www.yahoo.com"}
Dim counter As Integer = 0
Form3.Show()
Do Until counter = 3
Form3.WebBrowser1.ScriptErrorsSuppressed = True
Form3.WebBrowser1.Navigate(Urls(counter))
'MessageBox.Show("Next")
counter = counter + 1
System.Threading.Thread.Sleep(2000)
Loop
End Sub
You can call Application.DoEvents after changing the URL so that the control gets the chance to redraw itself.
However, a better approach would be to use a timer which fires every 2 seconds and then change the URL in the event handler so that your UI keeps responsive.
For example setup a new field myTimer in your form, init it in your form's loading event and in the Tick event you call your Rotate method. As Rotate is now called several times, we have to move the counter variable out of the method and make it a field so that we keep its value between the invocations. I usually write C# so hopefully I did not make some typos below :)
Private WithEvents myTimer As System.Windows.Forms.Timer
Private counter As Integer
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
' ... your existing code ...
counter = 0
myTimer = New System.Windows.Forms.Timer
myTimer.Interval = 2000
myTimer.Enabled = True
myTimer.Start()
End Sub
Private Sub myTimerTick() Handles myTimer.Tick
Rotate()
End Sub
Sub Rotate()
Dim Urls() As String = {"www.stackoverflow.com", "www.google.com", "www.yahoo.com"}
WebBrowser1.ScriptErrorsSuppressed = True
WebBrowser1.Navigate(Urls(counter))
counter = counter + 1
If counter > 3 Then myTimer.Stop()
End Sub

closing msaccess.exe in vb.net

I am working on creating a vb.net program i have a button that when clicked on will browse for MDB files (code 1) and when selected will execute some lines of code that will populate all of the macros within the access database into a combo box (code 2). The problem i'm having is MSACCESS.EXE process is not closing after code 2 runs. I've tried a couple different things like objAccess.CloseCurrentDatabase() none of which are working.. Any ideas on what i'm doing wrong?
code 1
Private Sub CommandDBPath_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles CommandDBPath.Click
Dim dialog As New OpenFileDialog()
dialog.Filter = "Access database (*.mdb)|*.mdb"
If DialogResult.OK = dialog.ShowDialog Then
TextDBPath.Text = dialog.FileName
End If
SelectDatabaseMacro()
End Sub
code 2
Private Sub SelectDatabaseMacro()
Dim objAccess As Object '' Access.Application
Dim i As Long
Dim path As String
path = TextDBPath.Text
objAccess = CreateObject("Access.Application")
objAccess.OpenCurrentDatabase(path)
For i = 0 To objAccess.CurrentProject.AllMacros.Count - 1
TextReportMacro.Items.Add(objAccess.CurrentProject.AllMacros(i).Name)
Next
objAccess.CloseCurrentDatabase()
objAccess = Nothing
End Sub
Try adding an objAccess.Quit statement after you objAccess.CloseCurrentDatabase().
To abruptly kill the process,
For Each p As Process In Process.GetProcesses()
If p.ProcessName = "MSAccess" Then
p.Kill()
End If
Next
Or for a more "graceful" approach, try this,
The process must have a windows interface (window) in order to work.
For Each p As Process In Process.GetProcesses()
If p.ProcessName = "MSAccess" Then
p.CloseMainWindow()
End If
Next

VB.NET - Running one sub multiple times at once

I have one Private sub that runs in a loop. I want the sub to run multiple times at once. For example the program runs, you press start; you run the program again and press start, again and again... the same program doing the job at once. now i just want one program do to it alone. But i would like it to be user defined. exp. run program. type in a text box 10. press start. and it works as if 10 of them work open working on the same thing.
I have seen another program made with vb.net 2010 and its what i use and do not know how to do it. so i am just wondering.
Private Sub Flood1(ByVal sender As Object, ByVal e As DoWorkEventArgs) Handles Flood.DoWork
Dim IP As IPAddress = IPAddress.Parse(TextBox1.Text)
Dim IPPort As New IPEndPoint(IP, Convert.ToInt32(TextBox2.Text))
Dim PacketS As Byte() = New Byte(TextBox3.Text) {}
Dim SocketN As Integer = Convert.ToInt32(TextBox4.Text)
Do While Flooding = True
For i = 0 To SocketN
If Flooding = True Then
Dim _Sock(i) As Socket
_Sock(i) = New Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp)
Try
_Sock(i).SendTo(PacketS, IPPort)
Threading.Thread.Sleep(500)
Catch ex As Exception
Threading.Thread.Sleep(500)
End Try
Else
Exit Do
End If
Next
Loop
End Sub
Mostly want to have this work over and over at once by the users choice... kinda hoped not to use this code else might not get helped.
You can use background worker for that.
Once you know how many workers you want to do the job
just create those many instances of background worker.
Tell me if this is the answer you are looking for or not
Sample Source Code
Imports System.ComponentModel
Module Module1
Sub Main()
Console.WriteLine("Please enter the worker count:")
Dim workerCount As Integer = Console.ReadLine()
For i As Int16 = 0 To workerCount
Dim worker As BackgroundWorker = New BackgroundWorker
worker.RunWorkerAsync(i + 1)
AddHandler worker.DoWork, AddressOf Worker_DoWork
Next
End Sub
Private Sub Worker_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs)
Console.WriteLine(e.Argument.ToString())
End Sub
End Module