Background
I am trying to think of how to logically tell if a process is complete. I currently have a separate program that generates a text file with then name "Information" for its title bar. When the information text file appears, the program is dumping a whole bunch of data to it. This can take a few seconds or many depending on the data. Basically I am trying to think of the best way for me to tell when that file is done being written to. Keep in mind that when I say text file, it is not the same as notepad as it does not have a physical file location. It is merely a part of the program that generates it.
Here is what I have so far:
<DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> Private Shared Function FindWindow(ByVal lpClassName As String, ByVal lpWindowName As String) As IntPtr
End Function
Dim proc As Integer
Do Until proc <> 0
proc = FindWindow(vbNullString, "Information")
Loop
I was thinking that I could possibly use the process ID and determine how much of the CPU it is using.. if it is high then the process is currently in use, and if low then it is done. The above code has no problem finding the process.
Is this a good approach to tell if it is done? If so, how do I determine CPU usage based on a process ID? There may be a better method than I am thinking of.
Process[] processes = Process.GetProcessesByName("ProcessName")
process = processes[0]
process.WaitForExit()
But that will freeze program until process it's done.
So incorporating background worker as Ayush said.
Private Sub StartButton_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles StartButton.Click
BackgroundWorker1.RunWorkerAsync()
End Sub
Private Sub BackgroundWorker1_DoWork(ByVal sender As System.Object, _
ByVal e As System.ComponentModel.DoWorkEventArgs) _
Handles BackgroundWorker1.DoWork
Process[] processes = Process.GetProcessesByName("ProcessName")
process = processes[0]
process.WaitForExit()
"you can put some code here for when it's done or below method.
End Sub
Private Sub BackgroundWorker1_RunWorkerCompleted(ByVal sender As System.Object, _
ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) _
Handles BackgroundWorker1.RunWorkerCompleted
"this will get called when bw done
End Sub
You can use the BackgroundWorker control in Visual Basic, it has an event called "Run Worker Completed" which will be raised when the task is successful, failed or cancelled.
Related
I've received a project from another developer. Long story short, the program pulls several thousand entries from an SQL Database hosted on our internal network. The program displays the entries and allows you to filter them for convenience.
Recently we had an issue in which a table in our SQL Database was cleared (It's normally regenerated each day, but for several days it was blank.) Found the issue and solved it (Made no changes to the VB project) to repopulate the table; but since that point the VB project would no longer fire events.
The program is several thousand lines of code long, so I can not post the entire thing; but I will try my best to give symptoms:
The form object can fire events (Form_Closing, Form_Closed, etc.)
The existing controls (Radio button, buttons, picturebox, data grid view, etc) will not fire any events.
If I add a new control (such as a button), it will not fire events.
If a put a debug breakpoint at the sub that should be fired, it will not break.
Here's an example of a method that should be fired but is not fired:
`Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
MsgBox("GOT IT!")
End Sub`
Here's the Form_Load sub:
<DllImport("user32.dll")> _
Private Shared Function SendMessage(ByVal hWnd As IntPtr, ByVal wMsg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer
End Function
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
InitializeComponent()
Try
DataGridView_Items.RowsDefaultCellStyle.SelectionBackColor = Color.Yellow
DataGridView_Items.RowsDefaultCellStyle.SelectionForeColor = Color.Black
CheckBox_Highlight.DataBindings.Add("Visible", RadioButton_BD, "Checked")
Try
'Populates the DGV
LoadTable()
TableLayoutPanel_BD_Parts.Visible = True
TableLayoutPanel_PF_Parts.Visible = False
'Exits if no data was pulled from the database
If dbDataSet.Rows.Count = 0 Or pfDataSet.Rows.Count = 0 Then Application.ExitThread()
Catch ex As Exception
Using w As StreamWriter = File.AppendText(logFile)
Log("Function Form1_Load says " & ex.Message & " # " & DateTime.Now.ToString("yyyy-MM-dd") & "_" & DateTime.Now.ToString("HH-mm-ss"), w)
End Using
End Try
BackgroundWorker1.RunWorkerAsync()
formLoaded = True
Catch exx As Exception
MsgBox(exx.ToString())
End Try
End Sub
There is a backgroundworker, but it appears to work correctly and exit out.
All the forms can be interacted with; but do not fire events. (I can change the selection of the radio button, click the button, type into text boxes, etc.)
I know this is a little vague, I'm just hoping someone can give suggestions as to things that could cause this that I can look into. I can provide specifics; but I can't copy the entire code here.
Thanks for any help!
A very strange thing in your code is that you call InitializeComponent() from Form_Load.
Usually this method is called in Form constructor so you can remove it from Form_Load.
I made some test on my PC: if you called twice InitializeComponent() you duplicate every controls in the form and their events doesn't fire anymore maybe because you have two controls with the same name.
I have a problem about a game. I want to play a background sound and another sound when you click a button. When this happens, the background sound stops and the 2nd sound starts. When the 2nd sound finishes, no sound will be played.
You can see my code below:
Imports System.Media.SoundPlayer
Public Class GamePlaying
Dim mainmenusndplayer As New System.Media.SoundPlayer
Private Sub GamePlaying_FormClosing(ByVal sender As System.Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles MyBase.FormClosing
MainMenu.Show()
mainmenusndplayer.Stop()
End Sub
Private Sub btn_Fire_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btn_Fire.Click
btn_Fire.Enabled = False
Dim shotsound As New System.Media.SoundPlayer
shotsound.Stream = My.Resources.TankShoot
shotsound.Play()
End Sub
Private Sub GamePlaying_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
mainmenusndplayer.Stream = My.Resources.WoT_Roll_Out
mainmenusndplayer.Load()
mainmenusndplayer.PlayLooping()
End Sub
End Class
I had been struggling with the same issue.....
The short answer is you can't. The system will only permit one channel to the sound interface within any given process. As such, when you start a new sound, the previous one terminates.
There are a number of work-arounds which mostly use either Direct-X or Media-Player. However, I found neither of those solutions to be either easy or robust in that you are depending on the users machine to have the right things installed.
However, I found a quick and simple solution to the problem.
I added a special "hook" to my application so that when I run it with an appropriate command line argument, all it does is play a particular sound and quit. I then use the process object to start another instance of the application with the appropriate argument.. and hey presto.. multiple sounds.
If your application is configured to automatically be be a single instance, you need to disable that and replace it with a little code to detect another instance and quit.
Another alternative is to add a small exe to your application package that simply does the sound part.
I know it does not sound very "pure", but really, all you are doing is starting a process to play a sound in the background. It doesn't really matter if that process is a windows native function or one of your own making.
you can use winmm.dll with mciSendString :
Imports System.Text
Imports System.Runtime.InteropServices
<DllImport("winmm.dll")>
Private Shared Function mciSendString(ByVal command As String, ByVal buffer As
StringBuilder, ByVal bufferSize As Integer, ByVal hwndCallback As IntPtr) As Integer
End Function
Private Sub MyForm_Click(sender As Object, e As EventArgs) Handles Me.Click
mciSendString("open " & Chr(34) & "C:\myFile1.wav" & Chr(34) " type waveaudio alias Sound1" & internalName, Nothing, 0, IntPtr.Zero)
mciSendString("open " & Chr(34) & "C:\myFile2.wav" & Chr(34) " type waveaudio alias Sound2" & internalName, Nothing, 0, IntPtr.Zero)
mciSendString("play Sound1", Nothing, 0, Me.Handle.ToInt64())
mciSendString("play Sound2", Nothing, 0, Me.Handle.ToInt64())
mciSendString("setaudio Sound1 volume to 1000", Nothing, 0, Me.Handle.ToInt64())
mciSendString("setaudio Sound2 volume to 1000", Nothing, 0, Me.Handle.ToInt64())
End Sub
and to stop the sounds you have to :
mciSendString("close Name1", Nothing, 0, Me.Handle.ToInt64())
mciSendString("close Name2", Nothing, 0, Me.Handle.ToInt64())
Download winmm.dll at https://www.dll-files.com/winmm.dll.html
I relise there is so many other questions out there regarding the progressbar, though I've looked through them "all" and can not find one that works.
I am trying to upload c:\screenshot.png to my ftp with a progress bar and a msgbox once finished.
Could someone provide a working example for me?
Thankyou
Edit heres the code I tried. Uploading works, though the progress bar dosent.
Sub UpdateProgressBar(ByVal sender As Object, ByVal e As UploadProgressChangedEventArgs)
If ProgressBar1.InvokeRequired Then
ProgressBar1.Invoke(New UploadProgressChangedEventHandler(AddressOf UpdateProgressBar), sender, e)
Exit Sub
End If
ProgressBar1.Value = CInt(ProgressBar1.Minimum + _
((ProgressBar1.Maximum - ProgressBar1.Minimum) * _
e.ProgressPercentage) / 100)
End Sub
Private Sub btnUpload_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button8.Click
Label16.Text = "Uploading now..."
Label16.Update()
Dim client As New System.Net.WebClient()
AddHandler client.UploadProgressChanged, AddressOf UpdateProgressBar
With client
.Credentials = New NetworkCredential( _
"damon#slimar.eu", "mine123!")
.UploadFile("ftp://slimar.eu/screenshot.png", "C:\screenshot.png")
End With
Label16.Text = "Done!"
Label16.Update()
End Sub
Progress bar has minValue,Max value, StepValue which is used to perform a step and Value to setup arbitray value.When you uploading a file or downloading you should be able to see via e paramenter total byte and actual byte trasmission.So you can setup Progress bar value and max value.
Also personally i invite you to use backgroundworker which :
Not Freeze GUI
Give you much controll on thread with no issue and no invoke needs
Make it more simple :)
I have a list of files displayed in a listbox.
when I select a file from the listbox i want the file to load into a panel on my form.
i.e. if its a word document word will open in the panel, if its a pdf reader wil open into the panel.
I can get the files to load externally using
Dim ProcStart As New ProcessStartInfo
ProcStart.FileName = ListBox1.SelectedItem
Process.Start(ProcStart)
however i am unsure of how to get it to then dock in my panel. I tried
Me.Panel1.Controls.Add(ProcStart)
but this is obviously wrong as I can't add a process as a control.
I did a bit of googleing and have tried to do it this way
<DllImport("user32.dll")>
Shared Function SetParent(ByVal hWndChild As IntPtr, ByVal hWndNewParent As IntPtr) As UInteger
End Function
Private Sub ListBox1_SelectedIndexChanged(sender As System.Object, e As System.EventArgs) Handles ListBox1.SelectedIndexChanged
Dim proc As Process
Dim AppPath As String
AppPath = lstDocs & ListBox1.SelectedItem
proc = Process.Start(AppPath)
proc.WaitForInputIdle()
SetParent(proc.MainWindowHandle, Me.Panel1.Handle)
End Sub
but the word application still opens outside my program and not in the panel!!
Any ideas? and thanks for looking!
Have you tried adding a button with code behind it to start the process?
'This is how i would start the process
this would be in your code that starts the control ( inserting )
Dim dep1 As (INSERT YOUR EVENT HERE)= New (INSERT YOUR EVENT HERE)
AddHandler dep.OnChange, AddressOf dep_onchange
the actuall button
Private Sub dep_onchange1(ByVal sender As System.Object, ByVal e As System.EventArgs)
' this event is run asynchronously so you will need to invoke to run on the UI thread(if required)
If Me.InvokeRequired Then
lbnoes.BeginInvoke(New MethodInvoker(AddressOf GetNoes))
Else
GetNoes()
End If
End Sub
I am trying to make a download manager for my program. But when I run this code it gives me the message box say "Download Started" but that is it. I do not get any file downloaded or progress bar change? Does anyone know why?
Public Class frmDownloader
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
WebClient1.DownloadFileAsync(New Uri("https://s3.amazonaws.com/MinecraftDownload/launcher/Minecraft_Server.exe"), "C:\hi.exe")
MsgBox("download started")
End Sub
Private Sub WebClient1_DownloadProgressChanged(ByVal sender As Object, ByVal e As System.Net.DownloadProgressChangedEventArgs) Handles WebClient1.DownloadProgressChanged
ProgressBar1.Value = e.ProgressPercentage
MsgBox("Download Progress Changed")
End Sub
End Class
The DownloadProgressChanged method is invoked on a different thread than the one that started the download. Inside this callback you seem to be manipulating some GUI element: ProgressBar1.Value. You should never manipulate GUI elements on different threads than the one on which they were created or you might get an exception. Depending on the type of application you are working on there are different ways to marshal calls on the GUI thread. For example in WinForms you should use the Control.BeginInvoke method. In WPF and Silverlight the equivalent is the Dispatcher.BeginInvoke.