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

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.

Related

Sub declaration within lambda expression doesn't work

I tried to run the following example from http://www.informit.com/articles/article.aspx?p=2429291&seqNum=8
Private progress As Progress(Of Integer)
Private counter As Integer = 0
Sub Main()
Try
progress = New Progress(Of Integer)
AddHandler progress.ProgressChanged, Sub(sender, e)
Console.
WriteLine _
("Download progress: " & _
CStr(e))
End Sub
DownloadAllFeedsAsync(progress)
Catch ex As Exception
Console.WriteLine(ex.Message)
Finally
Console.ReadLine()
End Try
End Sub
My problem is, that the following line is not accepted by the compiler:
AddHandler progress.ProgressChanged, Sub(sender, e)
Console.WriteLine("Download progress: " & CStr(e))
End Sub
There seems to be a problem with sender and e.
The error message is the following:
The Lambda-Parameter "sender" hides a variable in an embracing Block".
Does somebody know this problem?
As i mentioned in my comment to the question: i've checked related code on both VS: 2012 and 2017 and it's getting compiled without errors.
As to your error message, please check this: Lambda parameter '' hides a variable in an enclosing block, a previously defined range variable, or an implicitly declared variable in a query expression
The most important thing is:
To correct this error
Ensure that all variables in your lambda expression have unique
names that do not duplicate existing variable names in the same scope.
Accordingly to your comment:
In the example from the link there is only a Sub Main() whereas in my
example I have Form1_Load(Sender As Object, e as Eventargs).
So, variables: sender and e are existing in the same scope. Now, you know what to do to resolve your issue ;)

vb.net - error handling on main method or every method

I have a program that is interacting with emails. I am upgrading it from vb6 to vb.net. There was extensive error handling in the program before ,using On Error commands, to ensure that it never broke, just ignored and logged the errors. In most functions there is this On Error code, where it handles an error in the function by returning a default value and exiting the function. For Example:
Public Function Init() As Boolean
On Error GoTo Err_Init
Init = True
Exit_Init:
Exit Function
Err_Init:
Init = False
Resume Exit_Init
End Function
I want to change all error handling to Try - Catch blocks. My initial thought when I was upgrading the vb6 code was to replace all error handling with a simple Try - Catch around the Sub Main entry point, as below:
Public Sub Main()
Try
Init()
catch
'do stuff
end try
End Sub
public function Init() As boolean
init = true
end function
as any errors in the program would be caught in this way and I could handle them all in one Try - Catch.
However I then realised that, that would not make the function above return a value of False when an error occurred. If I still want this functionality do I have to wrap everything in Try blocks?
Since your concern is that you do not want the application to crash or break, Yes you can use Try cache block for that concern.
However, If you are talking about error handling in the whole application, then I would suggest that you think of a way to refactor the whole code.
Remove all the "On Error" statements and apply some new logic to handle the errors.
That logic could vary (Only logging, Retrying strategy Design pattern, etc) Think of all the expected errors and handle them accordingly.
If you need to do something special for errors in a particular function, then the function should have its own Try/Catch block to implement that behavior. For example:
Public Function Init() As Boolean
Try
'Presumably some other code goes here
Return True
Catch ex As Exception
Return False
End Try
End Function
Get rid of all the on Error steps and do the error handling globally
In the main_load put the three block below
' Get your application's application domain for error handling.
Dim currentDomain As AppDomain = AppDomain.CurrentDomain
' Define a handler for unhandled exceptions.
AddHandler currentDomain.UnhandledException, AddressOf MYExnHandler
' Define a handler for unhandled exceptions for threads behind forms.
AddHandler Application.ThreadException, AddressOf MYThreadHandler
and then add the two sub routines shown below
Private Sub MYExnHandler(ByVal sender As Object,
ByVal e As UnhandledExceptionEventArgs)
Dim EX As Exception
EX = e.ExceptionObject
If EX.StackTrace.Contains("SOMETHING") Then
My.Computer.FileSystem.WriteAllText(LogToWrite, "Error SOMETHING caught:" & EX.StackTrace & vbCrLf, True, System.Text.Encoding.Default)
MsgBox("error caught. Contact **XXX** for assistance!" & vbCrLf & vbCrLf & "Error: " & vbCrLf & EX.StackTrace,, "Fatal Error")
End If
End Sub
Private Sub MYThreadHandler(ByVal sender As Object,
ByVal e As Threading.ThreadExceptionEventArgs)
If e.Exception.StackTrace.Contains("SOMETHING") Then
My.Computer.FileSystem.WriteAllText(LogToWrite, "Error SOETHING caught:" & e.Exception.StackTrace & vbCrLf, True, System.Text.Encoding.Default)
MsgBox("Error caught. Contact **xxx** for assistance!" & vbCrLf & vbCrLf & "Error: " & vbCrLf & e.Exception.StackTrace,, "Fatal Error")
End If
End Sub
You can just check the content of the errors and respond accordingly to every single error with a Case Array..

How to catch exception when attempting to delete a file in use?

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.

Unhandled Exception error line and source function

I am using VS2012 VB.net.
Can I please have some help in creating some code to calculate the error line of an exception and also the function that the exception occurred in.
Here is my current code:
Partial Friend Class MyApplication
Public exceptionListOfExceptionsToNotPauseOn As New List(Of ApplicationServices.UnhandledExceptionEventArgs)
Private Sub MyApplication_UnhandledException(sender As Object, e As ApplicationServices.UnhandledExceptionEventArgs) Handles Me.UnhandledException
Dim msgboxResult As MsgBoxResult
Dim booleanExceptionFoundInList As Boolean = False
'Dim trace As System.Diagnostics.StackTrace = New System.Diagnostics.StackTrace(ex, True)
'Dim exceptionLineNumber = trace.GetFrame(0).GetFileLineNumber()
For x = 0 To exceptionListOfExceptionsToNotPauseOn.Count - 1
If exceptionListOfExceptionsToNotPauseOn(x).Exception.Message = e.Exception.Message Then
booleanExceptionFoundInList = True
End If
Next
If Not booleanExceptionFoundInList Then
msgboxResult = MessageBox.Show("An exception error has occured." & vbCrLf & "Error message: " & e.Exception.Message & vbCrLf & "Do you wish to pause on this exception again?", "Exception", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question)
If msgboxResult = Microsoft.VisualBasic.MsgBoxResult.No Then
exceptionListOfExceptionsToNotPauseOn.Add(e)
End If
End If
e.ExitApplication = False
End Sub
End Class
UPDATE
The code for the trace code uses an Exception data type where as the code for handling unHandled exceptions above has a parameter of "e As ApplicationServices.UnhandledExceptionEventArgs". Can I use the trace code with this data type? Do I need to cast it to an exception type? Or is it not possible?
I am not mastering in Vb.Net but previously i used below code, may be it can help you
[ex.StackTrace()]
Try
'Your Code goes here
Catch ex As Exception
MsgBox(ex.StackTrace())
End Try
Here are a couple of tips. First is to use PostSharp its a AOP kit that will let you trace all methods entry and exit using Attributes. This would direct you to the function straight away.
Another trick. Subscribing to the ThreadExceptionEventHandler actually does cause the debugger to break on unhandled exceptions! Hence temporarily comment out your MyApplication_UnhandledException and add a ThreadExceptionEventHandler
<STAThread> _
Public Shared Sub Main(args As String())
Try
'your program entry point
Application.ThreadException += New ThreadExceptionEventHandler(Application_ThreadException)
'manage also these exceptions
Catch ex As Exception
End Try
End Sub
Private Sub Application_ThreadException(sender As Object, e As ThreadExceptionEventArgs)
ProcessException(e.Exception)
End Sub
Another trick is is not to run under the debugger. The debugger is masking the exception for some reason. If you run your app normally (Ctrl+F5), you'll get the usual Unhandled exception has occurred in your application... Continue/Quit? dialog.
The code for handling unHandled exceptions above has a parameter of "e
As ApplicationServices.UnhandledExceptionEventArgs". Can I use the
trace code with this data type?
No.
You cannot easily use your trace code datatype with the UnhandledExceptionEventArgs. One idea might be to make a class that inherits from UnhandledExceptionEventArgs but I don't know how you'd call the MyApplication_UnhandledException function with the special type, because that function is invoked when an Exception is Unhandled.

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.