Does the VB ErrorObject work with try/catch blocks or just onError/GoTo? - vb.net

When converting onError/GoTo statements from VB6 into VB.Net, I've been told to use try/catch statements instead. Most of the VB6 error blocks utilize Microsoft.VisualBasic.ErrObject to provide the error code and description. For example:
CombinePDF_ERROR:
lErrorCode = Err
strErrorSource = Err.Source
strErrorDescription = Err.Description
bInProcess = False
strCombinePDFLastFile1 = strFile1
strCombinePDFLastFile2 = strFile2
ChDrive left$(strCurrentDir, 1)
ChDir strCurrentDir
Call CombinePDFUIUnload
Err.Raise lErrorCode, strErrorSource, strErrorDescription
End Sub
Does the Err (Microsoft.VisualBasic.ErrObject) get its information from the onError/GoTo statements? lErrorCode, strErrorSource, strErrorDescription aren't given values prior to this. How do I replicate this functionality in a try/catch? Catch an exception and messageBox the message? First time using VB6 or VB.Net. Thank you for your time.

That specific code in your question is basically like this Catch block below. The Err.Raise is equivalent to a Throw, and the Err object is roughly equivalent to an Exception object.
Catch ex
bInProcess = False
strCombinePDFLastFile1 = strFile1
strCombinePDFLastFile2 = strFile2
ChDrive left$(strCurrentDir, 1)
ChDir strCurrentDir
Call CombinePDFUIUnload
Throw ex
But that's just that one block. You need to check each VB6 error handler, work out what its doing, and work out the closest equivalent with Try Catch. You need to understand the VB6 On Error and the Err object, and also .Net Try...Catch and Exception object.
You are going to have a very hard time on this project if you don't know VB6 or VB.Net.

Related

BluetoothLEDevice.FromIdAsync Returns Uncastable __ComObject

Before we even start: In researching this problem I've looked at dozens of posts here and elsewhere, and realize that VB is the worst for Bluetooth programming. However, this is for a client who has a massive legacy VB system and I have no choice.
According to MS documentation, the BluetoothLEDevice.FromIdAsync is supposed to return a BluetoothLEDevice object but on my system it returns a generic System.__ComObject that I can't cast to a BluetoothLEDevice. I have tried Cast and DirectCast but neither work. The sample C++ code I've looked at doesn't require any type of casting; the variable is declared and set using the BluetoothLEDevice.FromIdAsync function without any dramas.
Here is my test code.
Private Sub ConnectToDevice(di As DeviceInformation)
'
' di.id = "BluetoothLE#BluetoothLE48:5f:99:3c:fd:36-84:2e:14:26:9e:7b"
'
Debug.Print("Connecting To " & di.Name & " at " & Now.ToShortTimeString)
Dim genericObject As Object
Dim myDevice As BluetoothLEDevice
Try
genericObject = BluetoothLEDevice.FromIdAsync(di.Id)
Catch ex As Exception
Debug.Print(ex.Message)
End Try
If Not IsNothing(genericObject) Then Debug.Print("Using 'Object' yeilds " & genericObject.ToString)
Try
myDevice = BluetoothLEDevice.FromIdAsync(di.Id)
Catch ex As Exception
Debug.Print(ex.Message)
End Try
End Sub
And here is the output:
Connecting To TM-2021090161 at 2:08 PM
Using 'Object' yeilds System.__ComObject
Exception thrown: 'System.InvalidCastException' in testBTLE.exe
Unable to cast object of type 'System.__ComObject' to type 'Windows.Devices.Bluetooth.BluetoothLEDevice'.
And a screen shot of the returned genericObject:
The FromIdAsync needs to be run async which I couldn't do because I got an error stating it didn't have an awaiter. It turns out that I needed to NuGet the System.Runtime.Windowsruntime dll. I added the Await and it's working now.
Thanks to Andrew for pointing me in the right direction.

Strange bug in MSHTML Assembly

Dim u As UInteger = 0
Try
Do
u += 1
j = DirectCast(o.item(d), HTMLTableRow).cells
Loop
Catch ex As Exception
MsgBox("Access No." & u & " throws:" & ex.GetType.ToString & ":" & ex.Message)
End Try
This is the piece of code I used as a test - a dead loop, infinitely accessing the variable O (assigned in code before) and assigning it to the variable J with some operation (O and J are both MSHTML.IHTMLElementCollection type). Under the debug mode, I can run it normally until the counter u reaches its upper limit. However, under the release mode, after loop for 5000~6000 times (in each test the number is different) it will throw "NullReferenceException". Note that I've just accessed O, never changed it, why is the exception? Is this a bug of MSHTML the assembly? Moreover, if I make a minor change:
Dim u As UInteger = 0, v As Object
Try
Do
u += 1
v = DirectCast(o.item(d), HTMLTableRow)
Loop
Catch ex As Exception
MsgBox("Access No." & u & "throws:" & ex.GetType.ToString & ":" & ex.Message)
End Try
That is, to remove the ".cells", and then there will be no exceptions. What's going on here? (This cannot be used as a workaround because in my program the ".cells" must be accessed)
If I use TryCatch block to ignore the exception and just try again, it won't run normally any more - throwing the exception for each loop. There must be some qualitative changes.
OK, MSHTML, you win. I have to use the dumbest workaround. Just try...catch the exception and try again. After numerous tests, I got the following possible exceptions that must be handled:
COMException, when you can simply try the statement throwing this again.
UnauthorizedAccessException, when you can simply try again like the last one.
NullReferenceException, when you CANNOT simply try again as you'll again catch the same exception. You'll have to initialize a new HTMLDocument and reload the URL, then do the remaining work.
Wanting anyone with a more elegant solution. I swear I'll never use the hideous Assembly if possible.

Setting a textbox property value within a catch block

Using VS 2013 VB.net for my ClickOnce application. I've got a function which verifies database functionality and the guts are wrapped in a Try Catch. A portion of my Catch block looks like this:
Catch ex As Exception When Err.Number = "5"
My.Application.Log.WriteException(ex)
If My.Settings.g_blnDebugMode Then
MessageBox.Show(Err.Number & " " & ex.ToString, "Exception Error")
End If
If Err.Description.Contains("The specified table does not exist") Then
MessageBox.Show("Selected file is not a valid database.", "Exception Error")
ElseIf Err.Description.Contains("The specified password does not match the database password.") Then
MessageBox.Show("The specified password does not match the current database password.", "Exception Error")
End If
Return False
What I want to do is, clear two different fields based on the two custom error messages at the bottom. Something like TextBox1.Text = "" or TextBox2.Text = "" depending on which error is thrown (invalid password or invalid database). My problem is that I don't seem to be able to set them directly or set the value of a module or global variable from within the catch block.
Error is:
Cannot refer to an instance member of a class from within a shared method or shared member initializer without an explicit instance of the class.
If it's possible how can I work around this and set my TextBoxes based on the results in the Catch block?
Usually the method to achieve what you are trying is to use a second a catch block
Catch ex As Exception When Err.Number = ""
MessageBox.Show(ex.Message)
FlushTextBox1();
Catch ex As Exception When Err.Number = ""
MessageBox.Show(ex.Message)
FlushTextBox2();
The error is likely appearing because the try-catch block is inside a Shared method. What that means is, the change in the value of TextBox will be repeated for all instances of the class. If you want the TextBox to behave like this, add the Shared keyword to its own declaration and remove it from the Sub's declaration. If you don't want this behaviour at all, just remove the Shared keyword. For more information on the error check the MSDN article
Alternatively you can call a local function (as shown in code) FlushTextBox1() to change the value of the TextBox outside the Sub.

How do I migrate CanPropertyChange("Text") from VB6 to VB.NET?

I want to upgrade an ActiveX control from VB6 to VB.NET. I'm having trouble upgrading this code:
If CanPropertyChange("Text") Then
Text1.Text = Value
RaiseEvent TextChange()
End If
I get the error: "Name 'CanPropertyChange' is not declared."
VB.Net does not support anything similar to the CanPropertyChange("Text") method. The easiest way around this is to do the assignment within a Try...Catch block.
Try
Text1.Text = Value
RaiseEvent TextChange()
Catch ex As Exception
End Try
If the property cannot be written to an exception will be thrown which you can access in the Catch block.

What error handling should be used in VB.NET

What error handling should be used in VB.NET?
Should one use the "On Error Goto ErrorHandler ... Exit Sub ErrHandler ... End Sub" pattern or should you use the "try { ... } catch { ... } finally { ... }" pattern?
"try { ... } catch { ... } finally { ...}" pattern by a long shot.
C#
try
{
// Do Something that may go wrong
}
catch (Exception ex)
{
//Do something with the error
}
finally
{
//Cleanup
}
or
VB
Try
// Do Something that may go wrong
Catch ex as Exception
//Do something with the error
Finally
//Cleanup
End Try
The most obvious reasons I can think of off the top of my head to steer clear of On Error GoTo... would have to be:
On Error GoTo does not discriminate between types of exceptions.
On Error GoTo does not provide as much structure as Try/Catch/Finally (e.g., nesting one Try/Catch block within another).
On Error GoTo has no counterpart to Finally (that I know of).
I'm sure in many cases, clever use of On Error GoTo could mimic the behavior that is built in to VB.NET's Try/Catch/Finally feature. But what would be the point?
On Error Goto ErrorHandler ... Exit Sub ErrHandler ... End Sub is from the VB6 days. Definitely go with Try... Catch... Finally...
A little background
'On Error Goto' is the way things were done in VB 6 before the .Net days. The VB compiler still allows this so you can easily port old VB code to VB.Net. VB.Net is probably the only .Net language that supports this.
'Try Catch Finally' is the .Net way to do things and a lot more flexible allowing you to catch, wrap and rethrow exceptions. It allows for easier interoperation between components written in different languages and is a lot more readable when you do more complex error handling because you don't have goto's.
Old post, but here's my two penneth. Debugging with On Error Goto is a lot easier than Try Catch:
On Error Goto ErrHand
do something that goes wrong
do something else
ErrHand:
Resume Next
Place a breakpoint on Resume Next and if it hits, step through your code once and you jump to the statement directly after the one that caused the exception, making it a lot easier to track down the problem.
On Error Goto is also good if you expect errors, like resources that are created by other processes that you are not in control of and aren't yet available, or locked resources when you know other processes will lock a resource and you must wait your turn. With On Error Goto you can wait for a bit and then Resume Retry, where Retry is a label in your code to try the operation again. When you look at code with that structure it's very obvious what's going on:
On Error Goto ErrHand
dim ErrCnt as Integer = 0
do something
RetryFile:
On Error Goto FileErr
download a file
On error Goto ErrHand
do something with the file
On Error Goto 0
Goto Done
FileErr:
ErrCnt += 1
if ErrCnt < 10 then
sleep for a while
Resume RetryFile
else
Throw New Exception("Can't download the file")
end if
ErrHand:
Throw New Exception(Err.Number & ": " & Err.Description)
Done:
tidy up
One last point. I use both structures as I do like the Try Catch nesting, but as can be seen from the above, similar functionality can by achieved with On Error Goto, and in some ways it's neater as it moves the error handling out of the flow of the main code and all into one place.