Error that can't be fixed? - vb.net

I'm getting an error in my VB.NET application that connects to my SQL database. It connects fine, but for some reason I can't fix this error. When I try to fix it, it moves from one part of my script to another part of my script (both of which were working yesterday). The error details are:
Unfortunately, it's difficult for me to describe how I produced this result, because it has happened in multiple parts of my code, and the only thing that these parts have in common is their interaction with Listbox1.
The first part of code to get this error was:
Dim sqlpage As MySqlCommand = New MySqlCommand("SELECT * FROM [" & frmMain.ListBox1.SelectedItem.value & "]", con)
Then I got the same exact error for:
Private Sub ListBox1_SelectedValueChanged( _
ByVal sender As Object, ByVal e As System.EventArgs) _
Handles ListBox1.SelectedValueChanged
Try
Form1.Label1.Text = ListBox1.SelectedItem
Form1.Show()
Catch myerror As MySqlException
MessageBox.Show("Error Setting Up Project Page: " & myerror.Message)
End Try
End Sub
More specifically:
Form1.Label1.Text = ListBox1.SelectedItem
And then I got it a few more times, but I think the examples above will suffice.
Since there are no "With Block Variables" in the examples above then the only other option is that it's object related. I've tried different methods of defining and redefining the object variables related to the error. However, the results are the same.
In response to Juxtaposition's answer, my original problem has been solved however two new problems have come up specifically because I turned Option Strict on.
The first is:
Error1: Option Strict On disallows late binding.
The code in question is:
Try
' Retrieving the projects list.
con.Open()
DataAdapter2.SelectCommand = sqlprojects
DataAdapter2.Fill(ds2, "projects")
ListBox1.Items.Clear()
For Each DataRow In ds2.Tables("projects").Rows
' Error occurs on the line below
ListBox1.Items.Add(DataRow("project_name"))
Next
con.Close()
Catch myerror As MySqlException
MessageBox.Show("Error Retrieving Projects List: " & myerror.Message)
End Try
The second is:
Error 2: Option Strict On disallows implicit conversions from 'Object' to 'String'.
The code in question is:
Private Sub ListBox1_SelectedValueChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles ListBox1.SelectedValueChanged
Try
If ListBox1.SelectedItem IsNot Nothing Then
' Error occurs on the line below
Form1.Label1.Text = ListBox1.SelectedItem
End If
Form1.Show()
Catch myerror As MySqlException
MessageBox.Show("Error Setting Up Project Page: " & myerror.Message)
End Try
End Sub
It worked out... so I thank all of you for your time and patience.

You should always (99.999999% of the time) write VB.NET code with Option Strict On, unless you are writing interop code or interfacing with an esoteric database provider.
Simply place the words "Option Strict On" at the top of your file.
This will allow you to catch errors like the one you are dealing with.
Without Option Strict On you are allowed to write code like you have written:
Form1.Label1.Text = ListBox1.SelectedItem
The issue with that code is that is implicity tries to convert an object (ListBox1.SelectedItem) to a string (Form1.Label1.Text).
Turn option strict on and the compiler will give you an error up front.
You will then be forced to rewrite your code as such:
If ListBox1.SelectItem IsNot Nothing then
Form1.Label1.Text = ListBox1.SelectedItem
End If

Focus on this line for the moment:
Form1.Label1.Text = ListBox1.SelectedItem
If you're getting a NullReferenceException on this line, then one of the following has to be true:
Form1 is null
Form1.Label1 is null
ListBox1 is null
You can try to determine this by adding lines like these just before the above line:
Console.Writeline("Form1: " & (Form1 Is Nothing))
Console.Writeline("Form1.Label1: " & (Form1.Label1 Is Nothing))
Console.Writeline("ListBox1:" & (ListBox1 Is Nothing))
You should see a line that outputs true; that's the first clue. But then the next question is, why is it null? From what you've shown so far, I can't say.

Make sure ListBox1.SelectedItem is not Nothing in both of those circumstances.

Your original errors can be fixed without having to use Option Explicit On. You need to ensure that the Listbox.SelectedItem has a value before using it. The code should be written as:
If frmMain.ListBox1.SelectedItem IsNot Nothing Then
Dim sqlpage As MySqlCommand = New MySqlCommand("SELECT * FROM [" & frmMain.ListBox1.SelectedItem.value & "]", con)
End If
and
Try
If ListBox1.SelectedItem IsNot Nothing Then
Form1.Label1.Text = ListBox1.SelectedItem
End If
Form1.Show()
Catch myerror As MySqlException
MessageBox.Show("Error Setting Up Project Page: " & myerror.Message)
End Try
Update #2
Your second error should be fixed by changing the code to:
If ListBox1.SelectedItem IsNot Nothing Then
Form1.Label1.Text = ListBox1.SelectedItem.ToString
End If
Option Explicit On means that you have to explicitly convert data types.

Related

Log Writer not creating new line for each entry

I get the feeling this is something really simple, but I've tried I don't know how many permutations of vbNewLine, Environment.NewLine, sMessage & vbNewLine (or Environment.Newline) I've tried, or how many pages on this site, or through Google I've looked at but nothing has worked.
I even tried getting help from a VB.Net discord channel I'm a part of and they suggested to do the same things that I've done and the procedure is still writing each new log entry at the end of the previous one in a continuous string. My writer is below. Am I missing something simple?
Edit: The code that worked is below in case anyone else comes along with the same issue. If you want to see the original code it's in the edit log.
Option Explicit On
Imports System.IO
Public Class WriteroLog
Public Shared Sub LogPrint(sMessage As String)
Dim AppPath As String = My.Application.Info.DirectoryPath
If File.Exists($"{AppPath}\Log.txt") = True Then
Try
Using objWriter As StreamWriter = File.AppendText($"{AppPath}\Log.Txt")
objWriter.WriteLine($"{Format(Now, "dd-MMM-yyyy HH:mm:ss")} – {sMessage}")
objWriter.Close()
End Using
Catch ex As Exception
MsgBox(ex)
Return
End Try
Else
Try
Using objWriter As StreamWriter = File.CreateText($"{AppPath}\Log.Txt")
objWriter.WriteLine($"{Format(Now, "dd-MMM-yyyy HH:mm:ss")} – {sMessage}")
objWriter.Close()
End Using
Catch ex As Exception
MsgBox(ex)
Return
End Try
End If
End Sub
End Class
The File.AppendText() method creates a new StreamWriter that is then used to append Text to the specified File.
Note, reading the Docs about this method, that you don't need to verify whether the File already exists: if it doesn't, the File is automatically created.
As a side note, when creating a Path, it's a good thing to use the Path.Combine method: it can prevent errors in the path definition and handles platform-specific formats.
Your code could be simplified as follows:
Public Shared Sub LogPrint(sMessage As String)
Dim filePath As String = Path.Combine(Application.StartupPath, "Log.Txt")
Try
Using writer As StreamWriter = File.AppendText(filePath)
writer.WriteLine($"{Date.Now.ToString("dd-MMM-yyyy HH:mm:ss")} – {sMessage}")
End Using
Catch ex As IOException
MsgBox(ex)
End Try
End Sub
The File.CreateText does not assign result to "objWrite", should be:
objWriter = File.CreateText($"{AppPath}\Log.Txt")
Not really sure if this is the root of your problem, but it is an issue.
In essences, your logic is re-opening or creating the stream "objWriter" for every call to this method. I would recommend you initialize "objWriter" to Nothing and only define if it is Nothing.
Set to Nothing as below.
Shared objWriter As IO.StreamWriter = Nothing
Then add check for Nothing in logic.

Unhandled Exception in Background Worker

Hi there I am carrying out some integration testing in an application I am developing. The specific element that is causing an issue is a call to a background worker which interrogates an Oracle database. When an error is encountered in the query I want the exception detail to percolate up the call stack to the application level and at that point provide an appropriate user compatible message. In the example test there is a syntax error in the underlying SQL which results in an OraEx Exception:
Oracle.DataAccess.Client.OracleException ORA-00907: missing right parenthesis
Unfortunately the code generates the following exception:
System.Reflection.TargetInvocationException was unhandled
Message: An unhandled exception of type
'System.Reflection.TargetInvocationException' occurred in mscorlib.dll
Additional information: Exception has been thrown by the target of an
invocation.
in the DoWork sub of the backgroundworker, despite my belief that I am handling the exception correctly. Its pretty obvious that I am missing something fundamental here, can someone suggest a solution please.
Thanks in Advance
Paul J.
Here is the code that makes the call to the background worker:
Private Sub EventSearch(ByVal mySQL As String)
Const procName As String = "EventSearch"
Try
_eventMngr = New ScadaEventManager(_CurrentDB, _userName, _myPwd)
_eventMngr.SQL = mySQL
'Set the flag and stop query tool status accordingly
_Stopped = False
uxStopQueryTool.Enabled = True
'activate the timer object to ensure that the execute query menu
'and tool remain disabled until all background processing is complete
uxBackWorkTimer.Enabled = True
_logger.SendLog(Me.Name & "." & procName & " - Scanning for data.", NLog.LogLevel.Trace)
ReviseStatus(2, "Scanning for data. Please wait...", Color.Black, True, True)
'Force the thread to sleep for half a second so the user can see the scanning state taking place
Threading.Thread.Sleep(500)
'Launch the background worker to retrieve the required data from the database
uxBWScan.RunWorkerAsync(_eventMngr)
Catch ex As Exception
MsgBox(ex.Message, MsgBoxStyle.Exclamation, My.Application.Info.ProductName)
_logger.SendLog(ex.Message & ". Thrown in module " & Me.Name.ToString & "." & procName, NLog.LogLevel.Error, ex)
Call ResetStatus()
Finally
End Try
End Sub
And here is the code executed by the background worker:
Private Sub uxBWScan_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles uxBWScan.DoWork
Const procName As String = "uxBWScan_DoWork"
Try
e.Argument.CountRecords(_queryTypeID)
e.Result = e.Argument.RecordCount
Catch NullEx As NullReferenceException
_logger.SendLog(NullEx.Message & ". Thrown in module " & Me.Name.ToString & "." & procName, NLog.LogLevel.Error, NullEx)
Throw
Catch OraEx As OracleException
_logger.SendLog(OraEx.Message & ". Thrown in module " & Me.Name.ToString & "." & procName, NLog.LogLevel.Error, OraEx)
Throw
Finally
End Try
End Sub
And here is the low level code that generates the error:
Public Sub CountRecords(ByVal queryType As Integer)
_myDataset = New DataSet
Try
_myDataset = _myScadaEventDB.CountRecords(_sqlText)
If _myDataset.Tables(0).Rows.Count > 0 Then
If queryType = Enums.QueryType.General Or queryType = Enums.QueryType.KeyPerformanceIndicators Or queryType = Enums.QueryType.TelecontroAnalysis Then
_recordCount = _myDataset.Tables(0).Rows(0).Item("RecordCount")
Else
'The query is grouped therefore count the number of records in the table
_recordCount = _myDataset.Tables(0).Rows.Count
End If
Else
_recordCount = 0
End If
Catch ex As Exception
Throw
Finally
End Try
End Sub
Ok, problem solved. Removed the try catch block from DoWork and moved my exception handling into 'RunWorkerCompleted' using e.error. Some reading of the documentation (RTFM...), highlighted the fact that using Try/Catch in the worker thread interferes with the native functionality of the BackgroundWorker. Thanks again everyone for your input.
Paul,

How do I handle NullReferenceException with my code

How do I handle this type of error or exception?
Try
If log.Trim = txtUSN.Text Then
MessageBox.Show("USN found: " & log)
Else
MessageBox.Show("USN not found: " & log)
End If
Catch ex as Exception
MessageBox.Show(ex.Message)
The message was "Object reference not set to an instance of an object."
This is the rest of the code:
Dim log As String
Dim sql As New SqlCommand
sql.Connection = MyConnection
sql.CommandText = "SELECT * FROM dbo.tblAcc WHERE USN = '" & txtUSN.Text & "' "
MyConnection.Open()
log = sql.ExecuteScalar
MyConnection.Close()
The simple answer is your trying to use an object that is nothing. If it's nothing you can't use it, hence "Object reference not set to an instance of an object."
As already mentioned in my comments above, the culprit is: log. I'm not sure where you have declared this or when your using it and how your using it, for all I know it's nothing. If you have more code that would be greatly appreciated as I can point out where it's nothing, until then here's how to get around your issue.
Try
If log IsNot Nothing Then
If log.Trim = txtUSN.Text Then
MessageBox.Show("USN found: " & log)
Else
MessageBox.Show("USN not found: " & log)
End If
Else
MessageBox.Show("Log is NOTHING!")
End If
Catch ex as Exception
MessageBox.Show(ex.Message)
End Try
**EDIT**
After you posted more code in a comment (please post code in the area, not in comment's) it seem's there are a few issue's. You have log defined as a string; when you do this set it to something like: String.Empty instead of nothing. Also you want to sse the ExecuteScalar method to retrieve a single value (for example, an aggregate value) from a database which could be an integer, long, single etc data types. In your query your selecting everything, you can't call ExecuteScalar to return that data... I would recommend looking up information about building queries and executing them, it's to long for me to get in depth with it here.
Happy Coding!
Make sure that (log) is not an empty string.
if not String.IsNullorEmpty(log) then
end if

Is there a difference between MsgBox and MessageBox.Show?

Is there a difference between the following two?
msgbox()
messagebox.show()
Some tutorials use msgbox(), and some use the other, messagebox.show()---I see that both can have an editable style, but I was wondering: Why are there two?
Is it to accommodate older programmers (who have learnt on an older version of Visual Basic)?
So in that case, which one should I use in Visual Basic 2010 (Visual Studio 2010)?
MsgBox() is the same as Messagebox.Show().
It exists for VB6 programmers who are used to it.
There are no rules on which one to use, but since MsgBox simply ends up delegating to MessageBox, I personally would go directly with MessageBox.
Here is the source code for Msgbox. As you can see it doesn't do anything particularly interesting before calling MessageBox.Show.
<MethodImpl(MethodImplOptions.NoInlining), HostProtection(SecurityAction.LinkDemand, Resources:=HostProtectionResource.UI)> _
Public Shared Function MsgBox(ByVal Prompt As Object, ByVal Optional Buttons As MsgBoxStyle = 0, ByVal Optional Title As Object = new Object()) As MsgBoxResult
Dim owner As IWin32Window = Nothing
Dim text As String = Nothing
Dim titleFromAssembly As String
Dim vBHost As IVbHost = HostServices.VBHost
If (Not vBHost Is Nothing) Then
owner = vBHost.GetParentWindow
End If
If ((((Buttons And 15) > MsgBoxStyle.RetryCancel) OrElse ((Buttons And 240) > MsgBoxStyle.Information)) OrElse ((Buttons And &HF00) > MsgBoxStyle.DefaultButton3)) Then
Buttons = MsgBoxStyle.OkOnly
End If
Try
If (Not Prompt Is Nothing) Then
[text] = CStr(Conversions.ChangeType(Prompt, GetType(String)))
End If
Catch exception As StackOverflowException
Throw exception
Catch exception2 As OutOfMemoryException
Throw exception2
Catch exception3 As ThreadAbortException
Throw exception3
Catch exception9 As Exception
Throw New ArgumentException(Utils.GetResourceString("Argument_InvalidValueType2", New String() { "Prompt", "String" }))
End Try
Try
If (Title Is Nothing) Then
If (vBHost Is Nothing) Then
titleFromAssembly = Interaction.GetTitleFromAssembly(Assembly.GetCallingAssembly)
Else
titleFromAssembly = vBHost.GetWindowTitle
End If
Else
titleFromAssembly = Conversions.ToString(Title)
End If
Catch exception4 As StackOverflowException
Throw exception4
Catch exception5 As OutOfMemoryException
Throw exception5
Catch exception6 As ThreadAbortException
Throw exception6
Catch exception13 As Exception
Throw New ArgumentException(Utils.GetResourceString("Argument_InvalidValueType2", New String() { "Title", "String" }))
End Try
Return DirectCast(MessageBox.Show(owner, [text], titleFromAssembly, (DirectCast(Buttons, MessageBoxButtons) And DirectCast(15, MessageBoxButtons)), (DirectCast(Buttons, MessageBoxIcon) And DirectCast(240, MessageBoxIcon)), (DirectCast(Buttons, MessageBoxDefaultButton) And DirectCast(&HF00, MessageBoxDefaultButton)), (DirectCast(Buttons, MessageBoxOptions) And DirectCast(-4096, MessageBoxOptions))), MsgBoxResult)
End Function
There is a difference when you are attempting to mix icons with different buttons. MsgBox has predefined styles (there may be a way to create new styles).
For example:
MsgBox("Do you wish to save changes?", MsgBoxStyle.YesNoCancel, "Save Changes")
^ This will display a box with Yes, No and Cancel buttons without an icon.
MsgBox("Do you wish to save changes?", MsgBoxStyle.Question, "Save Changes")
^ This will display a box with a Question mark icon but with ONLY an OK button.
MessageBox.Show("Do you wish to save changes?", "Save Changes", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question)
^ This will display a box with Yes, No and Cancel buttons AND a Question mark icon.
As you can see, using MessageBox.Show enables you to have any buttons you want with any icon.
But the really nice thing about MsgBox is that it can be SystemModal e.g. If MsgBox("There is a new Quick Message!" & Environment.NewLine & "Do you want to read it now?", MsgBoxStyle.Information + MsgBoxStyle.YesNo + MsgBoxStyle.SystemModal, "Quick Message") = MsgBoxResult.Yes Then...
I couldn't find a simple way of making If MessageBox.Show(... to be SystemModal.
My messages now get full prominence on screen. Yippee.
According to this site and the answers so far to my own question (see remark), as well my inability to display a specific help file using the msgbox function, I'd have to say use messagebox rather than msgbox if you want to show help. The msgbox function displays a help button, but apparently there is no way to put a helpfile in it! I'm showing the code I played around with below, and there is also a good code sample on the first link.
Imports Microsoft.visualbasic 'have to have this namespace to use msgbox
Public Class Form1
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim Helpfilepath As String = "C:\Windows\Help\mui\0409\aclui.chm"
Dim msgresult As Byte
'BTW, Must use 0 for BLANK PARAMETER. Using messageboxoptions.defaultdesktoponly errors out with help btn.
msgresult = MessageBox.Show("Text", "Messagebox", 0, _
0, 0, 0, Helpfilepath)
'displays help button, but how do you display the help file?
msgresult = MsgBox("Text", MsgBoxStyle.MsgBoxHelp, "msgbox")
'BTW, must use dialogresult rather than messageboxresult with windows forms
If msgresult = DialogResult.Yes Then
'etc
End If
End Sub
End Class
The message box created using MsgBox() has a title of the form which created it, whereas the message box window created by MessageBox.Show() does not have any title.

Building A True Error Handler

I am trying to build an error handler for my desktop application. The code Is in the class ZipCM.ErrorManager listed below.
What I am finding is that the outputted file is not giving me the correct info for the StackTrace.
Here is how I am trying to use it:
Try
'... Some stuff here!
Catch ex As Exception
Dim objErr As New ZipCM.ErrorManager
objErr.Except = ex
objErr.Stack = New System.Diagnostics.StackTrace(True)
objErr.Location = "Form: SelectSite (btn_SelectSite_Click)"
objErr.ParseError()
objErr = Nothing
End Try
Here is the class:
Imports System.IO
Namespace ZipCM
Public Class ErrorManager
Public Except As Exception
Public Location As String
Public Stack As System.Diagnostics.StackTrace
Public Sub ParseError()
Dim objFile As New StreamWriter(Common.BasePath & "error_" & FormatDateTime(DateTime.Today, DateFormat.ShortDate).ToString().Replace("\", "").Replace("/", "") & ".log", True)
With objFile
.WriteLine("-------------------------------------------------")
.WriteLine("-------------------------------------------------")
.WriteLine("An Error Occured At: " & DateTime.Now)
.WriteLine("-------------------------------------------------")
.WriteLine("LOCATION:")
.WriteLine(Location)
.WriteLine("-------------------------------------------------")
.WriteLine("FILENAME:")
.WriteLine(Stack.GetFrame(0).GetFileName())
.WriteLine("-------------------------------------------------")
.WriteLine("LINE NUMBER:")
.WriteLine(Stack.GetFrame(0).GetFileLineNumber())
.WriteLine("-------------------------------------------------")
.WriteLine("SOURCE:")
.WriteLine(Except.Source)
.WriteLine("-------------------------------------------------")
.WriteLine("MESSAGE:")
.WriteLine(Except.Message)
.WriteLine("-------------------------------------------------")
.WriteLine("DATA:")
.WriteLine(Except.Data.ToString())
End With
objFile.Close()
objFile = Nothing
End Sub
End Class
End Namespace
What is happenning is the .GetFileLineNumber() is getting the line number from objErr.Stack = New System.Diagnostics.StackTrace(True) inside my Try..Catch block. In fact, it's the exact line number that is on.
Any thoughts of what is going on here, and how I can catch the real line number the error is occuring on?
Edit: Changed the code to account for the Exception.StackTrace being a string rather than a real StackTrace
You're creating a new StackTrace, so then it will be for the line you're declaring it on, if you want the line number of the original exception, use the stack trace in Exception.StackTrace.
I think you're being a little confused, I can't see why you create the new StackTrace at all?
Edit: Added more bits to the answer here since easier to see the syntax than in a comment
Currently you have the line
objErr.Stack = New System.Diagnostics.StackTrace(True)
Which means that you're creating a whole new stacktrace, starting when you're creating it.
Instead change that line to:
objErr.Stack = New System.Diagnostics.StackTrace(ex, True)
Which will have the stacktrace from when the error actually happened.
Edit: Added complete sample:
Private Sub a1()
Try
a2()
Catch ex As Exception
Dim st As New StackTrace(True)
Debug.WriteLine(String.Format("ST after exception, will give line number for where st was created. Line No: {0}", st.GetFrame(0).GetFileLineNumber()))
st = New StackTrace(ex, True)
Debug.WriteLine(String.Format("ST after exception using exception info, will give line number for where exception was created. Line No: {0}", st.GetFrame(0).GetFileLineNumber()))
End Try
End Sub
Private Sub a2()
Dim st As New StackTrace(True)
Debug.WriteLine(String.Format("ST before exception, will give line number for where st was created. Line No: {0}", st.GetFrame(0).GetFileLineNumber()))
Dim b As Integer = 0
Dim a As Integer = 1 / b
End Sub
SOLVED: You should change the wrong instruction, of the original code:
.WriteLine(Stack.GetFrame(0).GetFileLineNumber())
with this new one:
.WriteLine(Stack.GetFrame(Stack.FrameCount - 1).GetFileLineNumber)
and you will see, it will return the exact Line_Number of code
where the run time error occurs!!
You do not need to include a Stack property for your ErrorManager, because you have access to the stack trace through the exception.
From experience, I would create a Shared Sub Write(ex As Exception, location As String) method on the ErrorManager, and call in your Catch statement as:
ZipCM.ErrorManager.Write(ex, "Form: SelectSite (btn_SelectSite_Click)")
This change results in cleaner code, reduces the need to write lots of code in each Catch statement, and allows you to change the implementation of Write without having to revisit/rework/refactor each Catch statement.
For instance, you can change the Write method to also call Debug.WriteLine(ex) so you can see which exceptions you are handling during debugging without having to open the file. Moreover, you may want to include WriteNotify method that displays a message box of the exception then calls the Write method to log the exception.