Why would an event be void? (Object reference not set to an instance of an object)

advertisements

I have a form with a button, a label and a progress bar, so that when I click the button it creates an instance of class b to run a process. Once the process is done it will call an EventHandler to show "done" in the main form's label!

I created an event (SetStatusEvent) of a delegate (SetStatus) to do this. And it seems fine when I call this event outside the EventHandler (usbforProcessExited) but when I call it from usbforProcessExited it gives an error -

object reference not set to an instance of an object

main form

public partial class main : Form
{
    b rsSet = new b();

    public main()
    {
        InitializeComponent();
        rsSet.SetStatusEvent += new RemoteS.SetStatus(updateStatus);
    }

    private void button1_Click(object sender, EventArgs e)
    {
        rsSet.FormatUSB();
    }

    private delegate void UpdateStatus(int i, string str, Color clr);

    private void SetStatus(int i, string str, Color clr)
    {
        this.progressBar1.Value = i;
        this.lbl_status.ForeColor = clr;
        this.lbl_status.Text = str;
    }

    private void updateStatus(int i, String msg, Color color)
    {
        object[] p = GetInokerPara(i, msg, color);
        BeginInvoke(new UpdateStatus(SetStatus), p);
    }

    private object[] GetInokerPara(int progress, string msg, Color color)
    {
        object[] para = new object[3];
        para[0] = progress;
        para[1] = msg;
        para[2] = color;

        return para;
    }
}

class b

class b
{
    public delegate void SetStatus(int i, string msg, Color color);
    public event SetStatus SetStatusEvent;

    System.Diagnostics.Process usbfor = new System.Diagnostics.Process();

    public void FormatUSB()
    {

        usbfor.StartInfo.FileName = @"usbformat.bat";
        usbfor.EnableRaisingEvents = true;
        usbfor.Exited += new EventHandler(usbforProcessExited);
        usbfor.Start();
    }

    public void usbforProcessExited(object sender, EventArgs f)
    {
        SetStatusEvent(100, "DONE", Color.Green); //ERROR HERE! (object reference not set to an instance of an object
    }
}

Where is the problem?


You have a race condition:

usbforProcessExited gets subscribed in the constructor of b and might be invoked before you called rsSet.SetStatusEvent += new RemoteS.SetStatus(updateStatus).

You should only call usbfor.Start() after you subscribed to SetStatusEvent.

A related problem is that the event will run on another thread. You should set rsSet.SynchronizingObject before starting the process so your event handler can modify the form without manually calling Invoke/BeginInvoke.