Intermittent NullReferenceException on StopWatch - vb.net

I have StopWatch which is defined in the Form Class. The event which is it used in, is called by a Timer:
Public Class frmMain
Dim WithEvents cTimer As New System.Threading.Timer(AddressOf TickTockFTP, Nothing, 0, 800)
Dim cswEV1 As New Stopwatch
...
When I start Debugging the application, as it is building, every few times, I get an error on a check to see if the StopWatch is running:
Private Sub TickTockFTP(state As Object)
If cswEV1.IsRunning Then
.....
The error is:
System.NullReferenceException: 'Object reference not set to an instance of an object.'
cswEV1 was Nothing.
It happens randomly. There is no pattern as to when I get the error.

Related

VB.NET: Thread-join never returns?

my problem is that in a WCF service (on a network call) the thread doesn't come back. Unfortunately, I don't get any return values for functions or code after the join method is not executed.
The WCF service itself has a web interface that creates a thread because a form with TreeView and AllowDrop activated there would later return an error:
System.InvalidOperationException: "DragDrop registration failed"
ThreadStateException: STA mode (Single Thread Apartment) must be set for the current thread before OLE calls can be made. Make sure that the main function is marked with STAThreadAttribute.
If, on the other hand, I start a sample project "WindowsApp56" (no WCF service), Form1 is opened by ClassLibrary7 and code according to the join method is activated. The message box "ready" is now displayed.
No errors are thrown with the web service, when the thread isn't coming back.
Project WindowsApp56:
Imports System.Threading
Imports ClassLibrary7
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim tmp As New Class1
Dim myobject As System.Threading.Thread = New Thread(New ThreadStart(AddressOf tmp.Main))
myobject.TrySetApartmentState(ApartmentState.STA)
myobject.Name = "Tester1"
myobject.Start()
If myobject.ThreadState <> ThreadState.Unstarted Then
myobject.Join()
End If
MsgBox("ready")
End Sub
End Class
ClassLibrary7:
Public Class Class1
Public Sub Main()
Dim a As New Form1
a.ShowDialog()
End Sub
End Class
Is the thread join method wrong? How can I "wait for" return values.
According to the error message: 'STA mode (Single Thread Apartment) must be set for the current thread before OLE calls can be made. Make sure that the main function is marked with STAThreadAttribute.'
Add the STAThreadAttribute attribute on the Main method.
Public Class Class1
<STAThread()>
Public Sub Main()
Dim a As New Form1
a.ShowDialog()
End Sub
End Class

Why doesn't VB.NET give the same "field initializer can't reference non-static member" warnings as C#?

I've been bitten several times by writing VB.NET code like this:
Public Class Form1
Private DoesntWork As New List(Of TextBox)({TextBox1, TextBox2})
Private Works As List(Of TextBox)
Public Sub New()
InitializeComponent()
Works = New List(Of TextBox)({TextBox3, TextBox4})
End Sub
End Class
where DoesntWork is initialized to a list with two members, both of which are Nothing even though the initializer says they should be TextBox1 and TextBox2 (which are, of course, controls on the form).
The equivalent C# code:
public partial class Form1 : Form
{
private List<TextBox> DoesntWork = new List<TextBox>(){textBox1, textBox2};
private List<TextBox> Works;
public Form1()
{
InitializeComponent();
this.Works = new List<TextBox>(){textBox3, textBox4};
}
}
gives the error
Error: A field initializer cannot reference the non-static field,
method, or property 'WindowsFormsApplication1.Form1.textBox1'
Why doesn't the VB compiler give the same error? It instead crashes at runtime, which is obviously worse.
Kvermeer, it's "simple". The VB Class initializes the variables as the "New()" method is called. In that matter, when the "New()" method creates the class, it sets it's value as "{TextBox1, TextBox2}", but the "InitializeComponents()" methods wasn't yet called, so "TextBox1" and "TextBox2" are still NOTHING.
On The class you wrote:
Public Class Form1
Private DoesntWork As New List(Of TextBox)({TextBox1, TextBox2})
Private Works As List(Of TextBox)
Public Sub New()
InitializeComponent()
Works = New List(Of TextBox)({TextBox3, TextBox4})
End Sub
End Class
The sequence followed by the program is:
Set "DoesntWork" as a new list os TextBoxes composed by the value of
TextBox1 and TextBox2 (but they are not initialized yet, so they're
both NOTHING).
Since "works" doesn't have a initial value, it's not
set.
Then call "InitializeComponent()" method (wrote on the
"Form1.Designer.vb" file (that initializes TextBox1 and TextBox2,
but not the list of "doesntwork", because it was initialized already
with 2 NOTHING references).
Set the "Works" variable.
End the "New()" method.

Object reference error on form build

I'm having issues debugging my project as i'm getting a "An error occurred creating the form. See Exception.InnerException for details. The error is: Object reference not set to an instance of an object."
It appears it relates to the following line
Private allfiles = lynxin.GetFiles("*.txt")
from the below declarations
Public Class Form1
Private numfiles As Integer
Private AllDetail() As FileDetail
Private allfiles = lynxin.GetFiles("*.txt")
Private AllDetails(allfiles.Count) As FileDetail
I'm needing these set so they can be accessed for all controls within Form1
I've read through the troubleshooting tips but cannot seem to fix the issue without moving the line back within the control its primarily used in

Cross-thread communication and field-updating in VB.NET

I'm having some trouble getting cross-thread communication/field-updating working properly in my VB.NET 2010 program. I'm trying to update a field on my main form whenever a thread that I've started throws an event. Here's a simplified version of my code:
My main form:
Public Class Main
' stuff
' Eventually, startProcessing gets called:
Private Sub startProcessing()
Dim processingClass = New MyProcessingClass("whatever")
AddHandler processingClass.processStatusUpdate, AddressOf handleProcessStatusUpdate
Dim processingThread = New Thread(AddressOf processingClass.process)
processingThread.Start()
End Sub
Private Sub handleProcessStatusUpdate(statusUpdate As String)
txtMainFormTextBox.Text = statusUpdate ' InvalidOperationException
' "Cross-threaded operation not valid: Control 'txtMainFormTextBox' accessed from a thread other than the thread it was created on"
End Sub
End Class
The class which raises the event:
Public Class MyProcessingClass
Private whatever As String
Public Event processStatusUpdate(status As String)
Public Sub New(inWhatever As String)
whatever = inWhatever
End Sub
Public Sub process()
' do some stuff
RaiseEvent processStatusUpdate(whatever)
End Sub
End Class
As you can see, the handler in my main class doesn't have access to the TextBox I need since it was triggered by a different thread (I think). I've tried a number of other approaches to get this working, including:
Moving the event handler to MyProcessingClass, and passing txtMainFormTextBox by reference (ByRef) to the class.
Having the actual thread start inside of MyProcessingClass instead of Main.
None of these have worked. Clearly there's a concept that I'm missing here. What's the best way to get this done? Thanks!
You need to update the textbox on the UI thread by calling BeginInvoke.
You should use the BackgroundWorker component, which does all of this for you.
Simply handle the DoWork and ProgressChanged events.

Handling VB.NET events in VB6 code

I have some VB6 code that instantiates a class which handles events that are being raised from a VB.NET component. The VB6 is pretty straightforward:
private m_eventHandler as new Collection
...
public sub InitSomething()
dim handler as EventHandler
set handler = new EventHandler
m_eventHandler.Add handler
...
m_engine.Start
end sub
Note that the event handler object has to live beyond the scope of the init method (which is why it is being stored in a Collection). Note also that m_engine.Start indicates the point in the program where the VB.NET component would start raising events.
The actual event handler (as requested):
Private WithEvents m_SomeClass As SomeClass
Private m_object as Object
...
Private Sub m_SomeClass_SomeEvent(obj As Variant)
Set obj = m_object
End Sub
Note that m_object is initialized when an instance of EventHandler is created.
The VB.NET code which raises the event is even simpler:
Public ReadOnly Property SomeProp() As Object
Get
Dim obj As Object
obj = Nothing
RaiseEvent SomeEvent(obj)
SomeProp = obj
End Get
End Property
My problem is that when I debug the VB6 program, the first time InitSomething gets called, the event will not be handled (the VB6 event handler is never entered). Subsequent calls to InitSomething does work.
Everything works as I would have expected when I run the program outside the debugger. At this point, I'm not even sure if this is something I should be worried about.
It may or may not be relevant but the VB.NET was converted from a VB6 using the Visual Studio code conversion tool (and subsequently manually cleaned up).
I've found that if you are writing .Net Components for Consumption in VB6 (or any other COM environment) the utilisation of Interfaces is absolutely criticial.
The COM templates that comes out of the box with VStudio leave a lot to be desired especially when you are trying to get Events to work.
Here's what I've used.
Imports System.Runtime.InteropServices
Imports System.ComponentModel
<InterfaceType(ComInterfaceType.InterfaceIsDual), Guid(ClientAction.InterfaceId)> Public Interface IClientAction
<DispId(1), Description("Make the system raise the event")> sub SendMessage(ByVal theMessage As String)
End Interface
<InterfaceType(ComInterfaceType.InterfaceIsIDispatch), Guid(ClientAction.EventsId)> Public Interface IClientActionEvents
<DispId(1)> Sub TestEvent(ByVal sender As Object, ByVal e As PacketArrivedEventArgs)
End Interface
<ComSourceInterfaces(GetType(IClientActionEvents)), Guid(ClientAction.ClassId), ClassInterface(ClassInterfaceType.None)> _
Public Class ClientAction
Implements IClientAction
Public Delegate Sub TestEventDelegate(ByVal sender As Object, ByVal e As PacketArrivedEventArgs)
Public Event TestEvent As TestEventDelegate
public sub New()
//Init etc
end sub
public sub SendMessage(theMessage as string) implements IClientAction.SendMessage
onSendMessage(theMessage)
end sub
Protected Sub onSendMessage(message as string)
If mRaiseEvents Then
RaiseEvent TestEvent(Me, New PacketArrivedEventArgs(theMessage))
End If
End Sub
end Class
I've been able to get COM and .Net consumers of the Assembly/Component to work properly with events and be able to debug in and out of the component.
Hope this helps.
Just something to try - I have an inherent distrust of "As New .."
Can you try
private m_eventHandler as Collection
public sub InitSomething()
dim handler as EventHandler
set handler = new EventHandler
If m_eventHandler Is Nothing Then
Set m_eventHandler = New Collection
End if
m_eventHandler.Add handler
...
m_engine.Start
end sub
Alas, I've got no idea why this works in normal execution and not in debug except some vague suspicions that it's to do with .NET being unable to instantiate the VBA.Collection object (MS recommends that you write a quick VB6 component to do so), but since you're not creating collections in .NET code, it is still just a vague suspicion.