How to catch exception when attempting to delete a file in use? - vb.net

I't making a program to delete the files in my temp folder. I've gotten as far as the code to delete the files, But I can't seem to figure out how to skip the files in use or catch the exception so that my program doesn't crash when it attempts to delete a file in use.
Here is the code I have so far:
Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
If CheckBox1.Checked = True Then
Dim s As String
For Each s In System.IO.Directory.GetFiles("C:\Users\" + System.Environment.UserName + "\AppData\Local\Temp")
System.IO.File.Delete(s)
Next s
End If
end sub

Use a Try/Catch block to catch errors (exceptions)
Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
If CheckBox1.Checked = True Then
Dim s As String
For Each s In System.IO.Directory.GetFiles("C:\Users\" + System.Environment.UserName + "\AppData\Local\Temp")
Try
System.IO.File.Delete(s)
Catch ex As Exception
Console.WriteLine("File could not be deleted : {0}", ex.Message)
End Try
Next s
End If
end sub
That will allow your program to ignore the error and continue processing the next items.

When an exception is thrown, once it is handled by the Catch, execution will jump to the End Try. Therefore, where you place the beginning and ending of your Try/Catch block is important. For instance:
Try
Dim s As String
For Each s In System.IO.Directory.GetFiles("C:\Users\" + System.Environment.UserName + "\AppData\Local\Temp")
System.IO.File.Delete(s)
Next s
Catch ex As IOException
End Try
In the above example, if any call to Delete fails, it will jump to the End Try and skip the rest of the iterations of the For loop (thereby skipping the rest of the files). However, consider this:
Dim s As String
For Each s In System.IO.Directory.GetFiles("C:\Users\" + System.Environment.UserName + "\AppData\Local\Temp")
Try
System.IO.File.Delete(s)
Catch ex As IOException
End Try
Next s
In this second example, it will jump to the End Try and then continue to the next iteration of the For loop (thereby continuing on the the next file in the list).
Also, as noted in the comments, above, you definitely ought to be using Path.GetTempPath to get the path to the temporary folder. You should not construct the path yourself, since it could change. For instance, Windows does not require that you user folder has to be under C:\Users. You can actually change that.

Related

Async Download file updating the gui

I am downloading a file using webclient handling DownloadProgressChanged and DownloadFileCompleted.
My code is working whenever I am not updating the gui with percentage,b but In case I am going to update just a single label with it, then it kind of freezing in random situations. Doesn't matter if the file is little or big.
Public WithEvents mclient As New WebClient
Private Sub Download()
Dim filepath As String = (filepath..)
mclient.Encoding = Encoding.UTF8
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12
mclient.Headers.Add(HttpRequestHeader.UserAgent, "")
mclient.DownloadFileAsync(New Uri(link), filepath)
End Sub
Private Sub mClient_DownloadProgressChanged(sender As Object, e As DownloadProgressChangedEventArgs) Handles mclient.DownloadProgressChanged
Try
'file website missing Content-Length, so getting the real size parsing html (real size=label7)
label1.text= ((e.BytesReceived) / 1048576).ToString("0.00") & "/" & Label7.Text
Catch ex As Exception
End Try
End Sub
Private Sub mClient_DownloadFileCompleted(sender As Object, e As AsyncCompletedEventArgs) Handles mclient.DownloadFileCompleted
Try
label2.text="Download ended"
Catch ex As Exception
End Try
End Sub
How can I keep label1.text updated without using it inside of DownloadProgressChanged?
If I use a variable on it, where can I keep it updated? I don't want to use a timer though..

Avoid files in use when automatically deleting files in VB.net

I'm trying to make something that cleans files, basically deletes everything inside the folder. I face an issue how ever, when trying to clean %temp%, I run in to the issue that some files are in use inside %temp% file. How can I avoid these? Or just make it so it creates an exception for files that are in use. Here is my code :
Private Sub Button6_Click(sender As Object, e As EventArgs) Handles Button6.Click
Dim directoryName As String = "C:\Windows\Temp"
For Each deleteFile In Directory.GetFiles(directoryName, "*.*", SearchOption.TopDirectoryOnly)
File.Delete(deleteFile)
Next
MsgBox("Temp Files Cleaned", MsgBoxStyle.Information)
End Sub
I also need it to permanently delete files, not just send to recycle bin.
Private Sub Button6_Click(sender As Object, e As EventArgs) Handles Button6.Click
Dim directoryName As String = "C:\Windows\Temp"
For Each deleteFile In Directory.GetFiles(directoryName, "*.*", SearchOption.TopDirectoryOnly)
Try
File.Delete(deleteFile)
Catch ex As IOException
Continue For
End Try
Next
MsgBox("Temp Files Cleaned", MsgBoxStyle.Information)
End Sub
The above code will swallow the "In use" error and go on with the deletion process.
As honeyboy says some like the following:
Try
File.Delete(deleteFile)
Catch fe As System.IO.IOException
'do something
Finally
End Try

Searching a drive with vb.net

I am making a program that searches your drive for an executable.
Private Sub Button1_Click_1(sender As Object, e As EventArgs) Handles Button1.Click
Dim di As New DirectoryInfo("C:\")
Dim files() As FileInfo
Dim a As Integer
Do While a = 0
Try
files = di.GetFiles("FileName.exe", SearchOption.AllDirectories)
Catch ex As UnauthorizedAccessException
End Try
If Not files Is Nothing Then
a = 1
End If
Loop
txt_Location.Text = files(0).FullName
End Sub
As soon as it hits the first UnauthorizedAccessException, it gets stuck in an infinite loop. How do I skip over the files that produce the exception?
EDIT:
This is what I have now:
Public Sub DirSearch(ByVal sDir As String)
Dim dir As String
Try
For Each dir In Directory.GetDirectories(sDir)
For Each file In Directory.GetFiles(dir, "Filename.exe")
ComboBox1.Items.Add(file)
Next
DirSearch(dir)
Next
Catch ex As Exception
Debug.WriteLine(ex.Message)
End Try
End Sub
Private Sub Button1_Click_1(sender As Object, e As EventArgs) Handles Button1.Click
DirSearch("C:\")
End Sub
You need recursion here which handles each folder.
EDIT: As requested by the OP, a little example:
Public Sub DirSearch(ByVal sDir As String)
Try
For Each dir as String In Directory.GetDirectories(sDir)
For Each file In Directory.GetFiles(dir, "yourfilename.exe")
lstFilesFound.Items.Add(file)
Next
DirSearch(dir)
Next
Catch ex As Exception
Debug.WriteLine(ex.Message)
End Try
End Sub
Also take a look at the following answers:
Looping through all directory's on the hard drive (VB.NET)
How to handle UnauthorizedAccessException when attempting to add files from location without permissions (C#)
Also note, if you have enough access rights, you could simplify your code to this:
Dim di as New DirectoryInfo()
Dim files = di.GetFiles("iexplore.exe", SearchOption.AllDirectories) 'already returns all files at once
And at last but not least:
Avoid having infinite loops. Like in your example, they can lead to broken code just because some circumstances aren't like you've expected them to be. Imagine your code has run on your PC and you deployed this software to a customer - horrible scenario. ;-)

vb.net timer and exception (try... catch) and memory leak

Scenario:
I've hundreds of applications instances running on client machines doing a certain job. Something like a cloud app.
Objective: When an error occur in any of them i want to report the error to an error-log database an quit silently the app to avoid user annoyance.
The problem:
I've migrate to VB.NET recently and don't know yet wich is the best aproach to error handle the code. Those instances are runing a routine under a timer.
Private Sub timerLifeSignal_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles timerLifeSignal.Tick
MAINSUB()
End Sub
Friend Sub MAINSUB()
frmSAN.timerLifeSignal.Enabled = False
...
'do the job
...
frmSAN.timerLifeSignal.Enabled = True
end sub
At first glance i've put try/catch into every single function but it leads to a memory leak since, AFIK, the exception object created was not disposed correctly.
So is there a way to make try/catch do not memory leak under these circumstances?
Thx,
UPDATE:
Basically what i was doing is something like:
Private Sub timerLifeSignal_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles timerLifeSignal.Tick
MAINSUB()
End Sub
Friend Sub MAINSUB()
Try
frmSAN.timerLifeSignal.Enabled = False
...
'do the job
...
frmSAN.timerLifeSignal.Enabled = True
Catch ex as Exception : gERRFUNC(" | MAIN | " & ex.Message) : End Try
end sub
friend sub dothejob
try
...
' really do the job
...
Catch ex as Exception : gERRFUNC(" | MAIN | " & ex.Message) : End Try
end sub
and so on... and finally (may here it's my mistake) another try/catch nested into here:
Public Sub gERRFUNC(Optional ByVal errorMSG As String = "")
Try
' log message on database
SQL = "INSERT INTO sanerrorlog VALUES (NULL, '" & currentMySQLTime() & "', '" & errorMSG & "');"
' function that open conn and execute the sql... working fine
' NOTE THAT INSIDE THE DORS FUNCTION THERE'S ALSO A TRY/CATCH USING THE SAME EX OBJECT.
DORS(SQL)
' clean up things
SQL = "DELETE FROM sannie WHERE sid=" & gMyID
DORS(SQL)
For i = 0 To UBound(gCONN)
If gCONN(i).State = ConnectionState.Open Then gCONN(i).Close()
Next
frmSAN.nfi.Visible = False
gWWB = Nothing
End
Catch E As Exception: End: End Try
End Sub
So... if i do this:
Private Sub timerLifeSignal_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles timerLifeSignal.Tick
Try
MAINSUB()
Catch ex as Exception : gERRFUNC(" | MAIN | " & ex.Message) : End Try
End Sub
Means all exceptions inside mainsub should be catched?
You have another way..
You can attach events to the app domain and main thread, in case it fails, to catch the errors.
Something like:
AppDomain.CurrentDomain.UnhandledException +=
CurrentDomain_UnhandledException;
Application.ThreadException +=
Application_ThreadException;
Application.ApplicationExit += Application_ApplicationExit;
with this in mind, every time an exception occurs, anywhere that it hasn't a catch by itself, will fall trough any of this ones...
Try/Catches by themselves don't cause memory leaks. Not finalizing something after a failure, which triggers a catch can however. By removing your try/catches, you've apparently exposed something else that does finalize, even though informally, the object which was causing a memory leak.
Ask yourself this, how could a directive in your code cause a memory leak? Try, nor Catch are references to an object, and thus could not cause memory consumption issue by themselves -- only by the logical path of the code they control.
Just for reference the memory leak problem occurs because of nested try/catch loops wich (by my mistake) uses the same variable as exception object.
To be more clear take the following example:
Public Sub gERRFUNC(Optional ByVal errorMSG As String = "")
Try
// do something wrong here
Catch E As Exception: gERRFUNC(ex.Message): End Try
End Sub
friend Sub gERRFUNC(msg as string)
Try
// call another external sub (wich eventually may also throw an execption)
// take note that the var 'E' is also referenced here and everywhere
// so as 'E' is set it enters on a Exception loop causing the 'memory leak' problem.
Catch E as Exception: End: End Try
End Sub
By removing the nested try/catch or by using a well structured error 'flow' may avoid these type of problem.
Best Regards,
Paulo Bueno.

Variable is not declared; it may be inaccessible due to its protection level

Today I decided to come up with a program that would be useful for me in VB.net (I have never coded in VB.net before). All is going fine up till this point but I have hit a snag with the error mentioned above. The problem is with the windowssevenexistsonsource boolean under the get get of profiles comment. I will also take any code criticism well as I would like to get out of bad practices before I start! (the sub does end but I have not included that code)
Code:
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
'Check that the entries required are not empty
If String.IsNullOrEmpty(sourceipaddress.Text) Or String.IsNullOrEmpty(destinationipaddress.Text) Then
MsgBox("Source or destination IP address is empty")
Exit Sub
End If
'First we need to establish the operating system of the source and destination
Try
Dim windowssevenexistsonsource As Boolean = IO.Directory.Exists("\\" & sourceipaddress.Text & "\c$\users")
Dim windowssevenexistsondestination As Boolean = IO.Directory.Exists("\\" & sourceipaddress.Text & "\c$\users")
Catch ex As Exception
MsgBox(ex.Message)
Exit Sub
End Try
'Now we need to get a list of profiles in the relevant directory and put them into an array
'Declare variables and empty the array
Dim Sourcedirectorylistarray, destinationdirectorylistarray As String()
Dim sourcedirectoryentry, destinationdirectoryentry As String
Dim Sourcerootpath, destinationrootpath As String
'Get List of Profiles
Try
If windowssevenexistsonsource = True Then
Sourcedirectorylistarray = System.IO.Directory.GetDirectories("\\" & sourceipaddress.Text & "\c$\users\")
destinationdirectorylistarray = System.IO.Directory.GetDirectories("\\" & destinationipaddress.Text & "\c$\users\")
Else
MsgBox("test")
End If
Catch ex As Exception
MsgBox(ex.Message)
Exit Sub
End Try
In declaring your variables windowssevenexitsonsource and windowssevenexistsondestination in your try block you are limiting their scope to the try block. Try declaring them at the beginning of your subroutine.