I have a project-wide exception handler in my Windows CE app that is logging this when my app crashes in a specific scenario:
Message: From application-wide exception handler: System.NullReferenceException: NullReferenceException
at HHS.FrmDelivery.ReaderForm_Activated(Object sender, EventArgs e)
at System.Windows.Forms.Form.OnActivated(EventArgs e)
at System.Windows.Forms.Form.WnProc(WM wm, Int32 wParam, Int32 lParam)
at System.Windows.Forms.Control._InternalWnProc(WM wm, Int32 wParam, Int32 lParam)
at Microsoft.AGL.Forms.DLG.MessageBox(String wszCaption, String wszBody, MessageBoxButtons mbtyp, MessageBoxIcon mbicon, MessageBoxDefaultButton defbtn, DialogResult& mbret)
at System.Windows.Forms.MessageBox.Show(String text, String caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton)
at HHS.FrmDelivery.buttonSave_Click(Object sender, EventArgs args)
So the problem seems to be in FrmDelivery.ReaderForm_Activated(), which is part of the form's code to deal with barcode scanning:
private void ReaderForm_Activated(object sender, EventArgs e)
{
ExceptionLoggingService.Instance.WriteLog("Reached frmDelivery.ReaderForm_Activated");
// If there are no reads pending on barcodeReader start a new read
if (!this.barcodeReaderData.IsPending)
{
this.StartRead();
}
}
In context, here is the entire barcode scanning-related code on that form:
public partial class FrmDelivery : Form
{
. . .
// Barcode stuff
private Symbol.Barcode.Reader barcodeReader;
private Symbol.Barcode.ReaderData barcodeReaderData;
private EventHandler barcodeEventHandler;
// </ Barcode stuff
// form's overloaded constructor
public FrmDelivery(NewDelivery newDel)
{
InitializeComponent();
. . .
textBoxUPC_PLU.Focus();
}
// Barcode scanning code
private void textBoxUPC_PLU_GotFocus(object sender, EventArgs e)
{
ExceptionLoggingService.Instance.WriteLog("Reached frmDelivery.textBoxUPC_PLU_GotFocus");
if (this.InitReader())
{
this.StartRead();
}
}
private bool InitReader()
{
ExceptionLoggingService.Instance.WriteLog("Reached frmDelivery.InitReader");
// If reader is already present then retreat
if (this.barcodeReader != null)
{
return false;
}
// Create new reader, first available reader will be used.
this.barcodeReader = new Symbol.Barcode.Reader();
// Create reader data
this.barcodeReaderData = new Symbol.Barcode.ReaderData(
Symbol.Barcode.ReaderDataTypes.Text,
Symbol.Barcode.ReaderDataLengths.MaximumLabel);
// Create event handler delegate
this.barcodeEventHandler = this.BarcodeReader_ReadNotify;
// Enable reader, with wait cursor
this.barcodeReader.Actions.Enable();
this.barcodeReader.Parameters.Feedback.Success.BeepTime = 0;
this.barcodeReader.Parameters.Feedback.Success.WaveFile = "\\windows\\alarm3.wav";
// Attach to activate and deactivate events
this.Activated += ReaderForm_Activated;
this.Deactivate += ReaderForm_Deactivate;
return true;
}
private void StartRead()
{
ExceptionLoggingService.Instance.WriteLog("Reached frmDelivery.StartRead");
// If we have both a reader and a reader data
if ((this.barcodeReader != null) && (this.barcodeReaderData != null))
{
// Submit a read
this.barcodeReader.ReadNotify += this.barcodeEventHandler;
this.barcodeReader.Actions.Read(this.barcodeReaderData);
}
}
private void BarcodeReader_ReadNotify(object sender, EventArgs e)
{
ExceptionLoggingService.Instance.WriteLog("Reached frmDelivery.BarcodeReader_ReadNotify");
Symbol.Barcode.ReaderData TheReaderData = this.barcodeReader.GetNextReaderData();
// If it is a successful read (as opposed to a failed one)
if (TheReaderData.Result == Symbol.Results.SUCCESS)
{
// Handle the data from this read
this.HandleData(TheReaderData);
// Start the next read
this.StartRead();
}
}
private void ReaderForm_Activated(object sender, EventArgs e)
{
ExceptionLoggingService.Instance.WriteLog("Reached frmDelivery.ReaderForm_Activated");
// If there are no reads pending on barcodeReader start a new read
if (!this.barcodeReaderData.IsPending)
{
this.StartRead();
}
}
private void ReaderForm_Deactivate(object sender, EventArgs e)
{
ExceptionLoggingService.Instance.WriteLog("Reached frmDelivery.ReaderForm_Deactivate");
this.StopRead();
}
private void HandleData(Symbol.Barcode.ReaderData readerData)
{
ExceptionLoggingService.Instance.WriteLog("Reached frmDelivery.HandleData");
textBoxUPC_PLU.Text = readerData.Text;
// now move off of it to next non-read-only textBox
textBoxPackSize.Focus();
}
private void StopRead()
{
ExceptionLoggingService.Instance.WriteLog("Reached frmDelivery.StopRead");
// If we have a reader
if (this.barcodeReader != null)
{
// Flush (Cancel all pending reads)
this.barcodeReader.ReadNotify -= this.barcodeEventHandler;
this.barcodeReader.Actions.Flush();
}
}
private void textBoxUPC_PLU_LostFocus(object sender, EventArgs e)
{
ExceptionLoggingService.Instance.WriteLog("Reached frmDelivery.textBoxUPC_PLU_LostFocus");
this.DisposeBarcodeReaderAndData();
}
private void DisposeBarcodeReaderAndData()
{
ExceptionLoggingService.Instance.WriteLog("Reached frmDelivery.DisposeBarcodeReaderAndData");
// If we have a reader
if (this.barcodeReader != null)
{
// Disable the reader
this.barcodeReader.Actions.Disable();
// Free it up
this.barcodeReader.Dispose();
// Indicate we no longer have one
this.barcodeReader = null;
}
// If we have a reader data
if (this.barcodeReaderData != null)
{
// Free it up
this.barcodeReaderData.Dispose();
// Indicate we no longer have one
this.barcodeReaderData = null;
}
}
...and here is the code that is called prior to the exception occurring. "Reached frmDelivery.buttonSave_Click" is logged, and I do see the "Delivery saved" but the app crashes immediately thereafter:
private void buttonSave_Click(object sender, EventArgs args)
{
ExceptionLoggingService.Instance.WriteLog("Reached frmDelivery.buttonSave_Click");
if (RequiredDataMissing())
{
this.IndicateMissingData();
return;
}
this.PrepareForNewDSDTable();
SaveDSDHeaderRecord();
SaveWorkTableRecord();
// Now can search the record
buttonFind.Enabled = true;
MessageBox.Show("Delivery saved");
}
...and here is an excerpt of the log file (from the time SaveWorkTableRecord() is called until the "deluge"):
Date: 3/13/2009 6:41:34 PM
Message: Reached frmDelivery.SaveWorkTableRecord
Date: 3/13/2009 6:41:34 PM
Message: Reached HHSUtils.TryConvertToInt32
Date: 3/13/2009 6:41:34 PM
Message: Reached HHSUtils.TryConvertToDecimal
Date: 3/13/2009 6:41:34 PM
Message: Reached SQliteHHSDBUtils.InsertWorkTableRecord
Date: 3/13/2009 6:41:34 PM
Message: Reached HHSUtils.GetDBConnection
Date: 3/13/2009 6:41:34 PM
Message: Reached frmDelivery.ReaderForm_Deactivate
Date: 3/13/2009 6:41:34 PM
Message: Reached frmDelivery.StopRead
Date: 3/13/2009 6:41:37 PM
Message: Reached frmDelivery.ReaderForm_Activated
Date: 3/13/2009 6:41:37 PM
Message: From application-wide exception handler: System.NullReferenceException: NullReferenceException
at HHS.FrmDelivery.ReaderForm_Activated(Object sender, EventArgs e)
at System.Windows.Forms.Form.OnActivated(EventArgs e)
at System.Windows.Forms.Form.WnProc(WM wm, Int32 wParam, Int32 lParam)
at System.Windows.Forms.Control._InternalWnProc(WM wm, Int32 wParam, Int32 lParam)
at Microsoft.AGL.Forms.DLG.MessageBox(String wszCaption, String wszBody, MessageBoxButtons mbtyp, MessageBoxIcon mbicon, MessageBoxDefaultButton defbtn, DialogResult& mbret)
at System.Windows.Forms.MessageBox.Show(String text, String caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton)
at HHS.FrmDelivery.buttonSave_Click(Object sender, EventArgs args)
at System.Windows.Forms.Control.OnClick(EventArgs e)
at System.Windows.Forms.Button.OnClick(EventArgs e)
at System.Windows.Forms.ButtonBase.WnProc(WM wm, Int32 wParam, Int32 lParam)
at System.Windows.Forms.Control._InternalWnProc(WM wm, Int32 wParam, Int32 lParam)
at Microsoft.AGL.Forms.EVL.EnterMainLoop(IntPtr hwnMain)
at System.Windows.Forms.Application.Run(Form fm)
at HHS.Program.Main()
Pay no attention to the dates; the handheld device is (somewhat fittingly) living in the past.
Here is the last successfully called method:
private void SaveWorkTableRecord()
{
ExceptionLoggingService.Instance.WriteLog("Reached frmDelivery.SaveWorkTableRecord");
WorkTable wt = new WorkTable
{
WTName = this.dsdName,
SiteNum = this.nd.SiteNum,
FileType = "DSD",
FileDate = this.nd.DeliveryDate,
TotalItems = HHSUtils.TryConvertToInt32(this.textBoxQty.Text.Trim()),
TotalAmount =
HHSUtils.TryConvertToDecimal(this.textBoxTotalDollar.Text.Trim())
};
hhsdbutils.InsertWorkTableRecord(wt);
}
So why is barcodeReader and/or barcodeReaderData (apparently) null, when they are instantiated in InitReader(), which is called when the form is constructed?
UPDATE
Even with the barcodereader and barcodereaderData code moved from where it was to FormClosing(), I still get an NRE:
Date: 3/13/2009 8:10:08 PM
Message: Reached frmDelivery.DisposeBarcodeReaderAndData
Date: 3/13/2009 8:10:08 PM
Message: Reached HHSUtils.TextBoxLostFocus
Date: 3/13/2009 8:10:08 PM
Message: Reached frmDelivery.buttonClose_Click
Date: 3/13/2009 8:10:12 PM
Message: Reached frmDelivery.ReaderForm_Deactivate
Date: 3/13/2009 8:10:12 PM
Message: Reached frmDelivery.StopRead
Date: 3/13/2009 8:10:13 PM
Message: Reached frmDelivery.BarcodeReader_ReadNotify
Date: 3/13/2009 8:10:13 PM
Message: From application-wide exception handler: System.NullReferenceException: NullReferenceException
at HHS.FrmDelivery.BarcodeReader_ReadNotify(Object sender, EventArgs e)
at System.Windows.Forms.Control.TASK.Invoke()
at System.Windows.Forms.Control._InvokeAll()
UPDATE 2
Update: I moved this code to FormClosing(), but then got an NRE on shutting down the app...?!? Commenting the code out there, too (barcodeReader and barcodeReaderData no longer being disposed/nullified anywhere) rectified the problem - no more NREs.