The code below is one (of three) examples of my grief. It is a simple OpenFileDialog() call which causes the program to crash. On XP, the crash occurs if the dialog stays open for several seconds. On Vista, the crash occurs if the user selects "My Computer". In VS2008, the debugger sometimes catches a stackoverflowexception. If I put a break point in the first line (new ...), vshost.exe crashes. If I put a break point at the ShowDialog() line, I get a FatalExecutionEngineError. If I compile without vshost, the application will run until a random crash (as on XP - there is some amount of time).
There are two other open dialogs that open different types of files, all three of which have the same behavior. Similar code does not show the same behavior in my other projects.
The thread apartment is single. I have tried setting ValidateNames = false. The debugger is falling off the deep-end in most cases.
OpenFileDialog imageDlg = new OpenFileDialog();
imageDlg.Filter = "All Images|*.jpg;*.jpeg;*.png;*.tif;*.tiff;*.bmp|All Files|*.*|JPEGs (*.jpg)|*.jpg|PNGs (*.png)|*.png|TIFFs (*.tiff)|*.tiff|TIFFs (*.tif)|*.tif|BMPS (*.bmp)|*.bmp";
imageDlg.Title = "Select Scan Image";
if (DialogResult.OK == imageDlg.ShowDialog())
{
updateImageDisplay();
}
Event handler code:
//
// setScratchImageButton
//
this.setScratchImageButton.Location = new System.Drawing.Point(191, 15);
this.setScratchImageButton.Name = "setScratchImageButton";
this.setScratchImageButton.Size = new System.Drawing.Size(26, 23);
this.setScratchImageButton.TabIndex = 8;
this.setScratchImageButton.Text = "...";
this.setScratchImageButton.UseVisualStyleBackColor = true;
this.setScratchImageButton.Click += new System.EventHandler(this.setScratchImageButton_Click);
Code called
private void updateImageDisplay()
{
if (null != project.srcImage)
{
imageDisplay.SizeMode = PictureBoxSizeMode.Normal;
if (project.srcImage != null)
{
imageDisplay.ClientSize = new Size(project.srcImage.Width, project.srcImage.Height);
imageDisplay.Image = (Image)project.srcImage;
}
this.ScratchImage.Text = project.srcImageLocation;
}
else
{
imageDisplay.Image = null;
this.ScratchImage.Text = "";
}
ImageDisplayPanel.Refresh();
}
Under what circumstances is the method which displays this dialog being called? The most likely source of this error is that the event is being generated many times and causing many instances of OpenFileDialog to be displayed to the user. They are potentially being displayed on top of each other giving the appearance of only a single dialog.
EDIT
If it's only the debugger scenario that is failing then try turning off implicit function evaluation into debugger property windows (Tools -> Options -> Debugger). It's possible one of the properties on your form is causing a stack overflow when viewed through the debugger.
A DLL I had added to the project was causing heap corruption. The symptom was strange and beautiful crashes.
Related
I've been stuck on this all day, so I'm going to post everything I've been able to find today that might be useful to helping me, it will be a long post. I'm having 2 issues that I believe are related to the same problem. First, let me explain what I am doing. I have 3 Winforms combo boxes that are bound to lists of all of the devices found by MMDeviceEnumerator. Two output device boxes, one input device. I am using the MMDeviceEnumerator to register a callback for whenever the devices are changed, removed, or a default device is set. The callback fires an event that then invokes a delegate to the form thread to re-enumerate the devices into combo boxes. It looks like this:
public void OnDefaultDeviceChanged(DataFlow dataFlow, Role deviceRole, string defaultDeviceId)
{
Devices.OnDevicesUpdated();
}
//The handler called by this event:
private void UpdateDeviceSelectors(object? sender = null, EventArgs? e = null)
{
Invoke(delegate ()
{
int primaryIndex = Devices.PrimaryOutput + 1, secondaryIndex = Devices.SecondaryOutput + 2, microphoneIndex = Devices.Microphone + 1;
Devices.Refresh();
try
{
SecondaryOutputComboBox.SelectedIndex = secondaryIndex;
PrimaryOutputComboBox.SelectedIndex = primaryIndex;
MicrophoneSelectComboBox.SelectedIndex = microphoneIndex;
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
});
}
Now for the two issues I have. The first one involves a semi-random crash that leads back to NAudio.Wasapi.dll, where a System.ExecutionEngineException is thrown. It is kind of easy to reproduce. All I do is change the values of the combo boxes, switch the default devices around, and it will randomly crash.
The second issue occurs when another part of my code is involved. I have a microphone injector, which redirects a WaveInEvent that records a selected input device to a WaveOutEvent, like a loopback. Here is the relevant code for this:
public void Start()
{
if (Soundboard.Devices.SecondaryOutput == -2) return;
micStream = new WaveInEvent();
micStream.BufferMilliseconds = 50;
micStream.WaveFormat = new WaveFormat(44100, WaveIn.GetCapabilities(Soundboard.Devices.Microphone).Channels);
micStream.DeviceNumber = Soundboard.Devices.Microphone;
WaveInProvider waveIn = new(micStream);
var volumeSampleProvider = new VolumeSampleProvider(waveIn.ToSampleProvider());
volumeSampleProvider.Volume = 1 + Settings.Default.MicrophoneGain;
virtualCable = new WaveOutEvent();
virtualCable.DesiredLatency = 150;
virtualCable.DeviceNumber = Soundboard.Devices.SecondaryOutput;
virtualCable.Init(volumeSampleProvider);
micStream.StartRecording();
virtualCable.Play();
}
public void Stop()
{
try
{
if (micStream != null && virtualCable != null)
{
micStream.Dispose();
micStream = null;
virtualCable.Dispose();
virtualCable = null;
}
}
catch
{
micStream = null;
virtualCable = null;
}
}
In the delegate mentioned earlier, I am calling the Stop method of the Mic Injector and then the Start method to refresh the WaveIn and WaveOut devices to use the current device numbers so users do not see a device selected when a different device is being used. When this happens, the program, rather than crashing instantly and inconsistently, always hangs and has to be killed from the task manager. I am certain these 2 problems are related to the same root cause, but I have no idea what that root cause may be. Switching to Wasapi, DirectSound, or ASIO won't work because they lack certain functionalities I need, so I would really like to get this working still using Wave streams.
I've tried to find different ways to detect the device changes, assuming it is an issue deep inside NAudio, but I just can't find anything else. For the second problem specifically, I have moved the calls to the Mic Injector around thinking it may be a threading issue or something, but it didn't work or change the behavior.
I'm coding a medium winforms application... every now and then on creation of certain Forms i get this exception.
I resolved it in the past but without proper udnerstanding of what is going on...
The puzzling part is that everything worked fine yesterday when I finnished this form and tested it, now I get this:
An unhandled exception of type 'System.OutOfMemoryException' occurred
in System.Windows.Forms.dll
Additional information: Error creating window handle.
Exception is thrown in this block of code:
public partial class PonovniIspisRacunaForm : Form
{
DataTable dnevniPrometTable;
DataTable kontrolnaTrakaTable;
DataTable ukupniDnevniPrometTable;
DataTable stavkeRacunaTable;
ZisCode.Hibernate.Mdb.DataModel dnevniPrometDataModel;
ZisCode.Hibernate.Mdb.DataModel kontrolnaTrakaDataModel;
OsnovniPodaci.Porezi.Stope stope;
string brojRacuna;
string ZKI;
string JIR;
string Operator;
//decimal ukupno = 0.00m;
decimal tarifa;
decimal kolicina;
decimal iznos;
decimal porez;
decimal porez25;
decimal porez05;
decimal porez13;
decimal povratnaUkupno;
decimal osnov25;
decimal osnov05;
decimal osnov13;
//decimal nabavna;
PrintDocument printDocument;
public PonovniIspisRacunaForm()
{
InitializeComponent();
}
private void FinancijskiRekapitular_Load(object sender, EventArgs e)
{
stope = new OsnovniPodaci.Porezi.Stope();
// popunjava današnji datum
this.dtpDatum.Value = DateTime.Today;
// Get Data Table za određeni datum:
dnevniPrometDataModel = ZisCode.DataModels.Get("DnevniPromet");
kontrolnaTrakaDataModel = ZisCode.DataModels.Get("KontrolnaTraka");
PrintSetup();
ukupniDnevniPrometTable = MergeDnevniKontrolna();
if (ukupniDnevniPrometTable.Rows.Count != 0)
{
FillComboBox();
}
}
private void FillComboBox()
{
cbBrojRacuna.DataSource = ZisCode.Methods.DataTableOperations.SortDataTable(ukupniDnevniPrometTable, "Dokument", "DESC") // orderbydescending
.AsEnumerable().GroupBy(row => row.Field<string>("Dokument")).Select(group => group.First()).CopyToDataTable(); // groupby brojRacuna-Dokument
cbBrojRacuna.DisplayMember = "Dokument"; // Broj Računa
cbBrojRacuna.ValueMember = "Dokument";
cbBrojRacuna.SelectedIndex = 0;
}
private void PrintSetup()
{
// priprema za ispis
printDocument = new PrintDocument();
printDocument.DefaultPageSettings.PaperSize = new PaperSize("Racun size", 295, 500);
printDocument.PrintPage += new System.Drawing.Printing.PrintPageEventHandler(CreateRekapitular);
// uklanja poruku dialog box (printing ..) kod ispisa
PrintController printController = new StandardPrintController();
printDocument.PrintController = printController;
// popravlja font
printPreview.UseAntiAlias = true;
}
}
to be more specific this line: this.dtpDatum.Value = DateTime.Today;
Why?? I have no idea...
I tried seting dateTimePicker in constructor and I got different exception unrelated to window handle.
I've read about this case on other questions but nothing really clicked for me.
Winforms issue - Error creating window handle
Error Creating Window Handle
These two answers don't help me since answers are to ambiguous and expect me to know how dispose is supposed to work in first place. Help, I'm a n00b!
UPDATE Posted Almost all code of the class as I was asked
A window handle is an unmanaged resource. There are only so many of them. If you don't free those handles, Windows will run out and you will get exceptions.
Classes that use native HANDLEs will need to free them when they are no longer needed. Those classes will implement IDisposable. You should look into this, it's a core part of .NET and crucial to working with unmanaged resources like handles.
Turn on your static code analysis (Right click on Project -> Properties -> Code Analysis and select Enable on build and pick Microsoft all rules) and fix all violations, especially those non-disposed IDisposables.
Since your exception is OutOfMemory it may be that you are just out of memory. Check task manager to see how much memory you have available and I would suggest to run your app through some memory profiler like RedGate or something similar to see where the leak is. In case of dispose take a look at this asnwer for more info C# Form.Close vs Form.Dispose
The problem was private void
dtpDatum_TextChanged(object sender, EventArgs e)
{
ukupniDnevniPrometTable = MergeDnevniKontrolna();
FillComboBox();
}
I guess this event was fired up too many times and caused memory leak
As Peter Duniho points out in a comment here, I was fixated on a red herring when I should have been focusing on something else altogether.
When I use Symbol.Barcode.Reader and Symbol.Barcode.ReaderData in one form, they work fine. I use them as I document here.
However, when I go from one form that uses the barcode scanning code to another one that also does, all Dallas breaks loose. I get the following exception in the second form, on startup:
Symbol.Exceptions.OperationFailureException: SCAN_GetInterfaceParams
at Symbol.Barcode.InterfaceParams.GetInterfaceParams()
at Symbol.Barcode.InterfaceParams..ctor(Reader reader)
at Symbol.Barcode.Actions.Enable()
at HHS.frmFind.InitReader()
at HHS.frmFind.textBoxScan_GotFocus(Object sender, EventArgs e)
at System.Windows.Forms.Control.OnGotFocus(EventArgs e)
at System.Windows.Forms.Control.WnProc(WM wm, Int32 wParam, Int32 lParam)
at System.Windows.Forms.Control._InternalWnProc(WM wm, Int32 wParam, Int32 lParam)
at Microsoft.AGL.Forms.WL.SetVis(IntPtr hwnThis, BOOL fVis)
at System.Windows.Forms.Control.set_Visible(Boolean value)
at System.Windows.Forms.Form.ShowDialog()
The barcode scanning code between the two forms is identical, so it's not the code itself (it works fine the first time, in the first form).
The exception occurs immediately in the second form when the textbox that is set up for scanning is entered. It's GotFocus() event fires because the textbox gets focus when the form is displayed; OnGotFocus() calls InitReader(), which then fails. InitReader() is:
private bool InitReader()
{
ExceptionLoggingService.Instance.WriteLog("Reached frmFind.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;
}
The objects being dealt with there are in Symbol.Barcode.dll, from Motorola. They are declared in the form like so:
private Symbol.Barcode.Reader barcodeReader;
private Symbol.Barcode.ReaderData barcodeReaderData;
If I bypass the first form, which has the same type of barcode scannig code, and go straight to this form, it doesn't crash.
So apparently it's that the closely related bits of code can't coexist. Why not and, more importantly, how can I prevent this revolting development?
UPDATE
With this logging added to InitReader:
private bool InitReader()
{
ExceptionLoggingService.Instance.WriteLog("Reached frmFind.InitReader");
// If reader is already present then retreat
if (this.barcodeReader != null)
{
return false;
}
// Create new reader, first available reader will be used.
ExceptionLoggingService.Instance.WriteLog("Reached frmFind.InitReader #2");
this.barcodeReader = new Symbol.Barcode.Reader();
// Create reader data
ExceptionLoggingService.Instance.WriteLog("Reached frmFind.InitReader #3");
this.barcodeReaderData = new Symbol.Barcode.ReaderData(
Symbol.Barcode.ReaderDataTypes.Text,
Symbol.Barcode.ReaderDataLengths.MaximumLabel);
// Create event handler delegate
ExceptionLoggingService.Instance.WriteLog("Reached frmFind.InitReader #4");
this.barcodeEventHandler = this.BarcodeReader_ReadNotify;
// Enable reader, with wait cursor
ExceptionLoggingService.Instance.WriteLog("Reached frmFind.InitReader #5");
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
ExceptionLoggingService.Instance.WriteLog("Reached frmFind.InitReader #6");
this.Activated += ReaderForm_Activated;
this.Deactivate += ReaderForm_Deactivate;
ExceptionLoggingService.Instance.WriteLog("Reached frmFind.InitReader #7");
return true;
}
...I see this in the log file after opening the Find form and crashing the app (it hangs for about 20 seconds before disappearing):
Date: 3/19/2009 11:43:38 PM
Message: Reached frmFind.InitReader
Date: 3/19/2009 11:43:38 PM
Message: Reached frmFind.I
...so it's crashing almost instantaneously after this block of code:
if (this.barcodeReader != null)
{
return false;
}
...as it only gets through half of the next logging line before rudely interrupting itself.
UPDATE 2
Fejesjoco may still be right (in his comment below), but I submit this logging code as exhibit "A":
public void WriteLog(string message)
{
if (!HHSConsts.Logging) return;
StringBuilder formattedMessage = new StringBuilder();
formattedMessage.AppendLine("Date: " + DateTime.Now.ToString());
formattedMessage.AppendLine("Message: " + message);
_streamWriter.WriteLine(formattedMessage.ToString());
_streamWriter.Flush();
}
The stream should get flushed after each line is written to the log.
UPDATE 3
The failure is always very consistent as to how long it "hangs" before it crashes; I can see the cursor blinking in the bar code text box of the find form, and it pulsates about 20 times (I actually counted it last time: 24).
This also is a bit odd; in Update 2, I showed the contents of the log file with all the log entries sprinkled into the InitReader method. With those commented out (except for the first one), the log file ends with:
Date: 3/20/2009 12:01:22 AM
Message: Reached frmFind.InitReader
Date: 3/20/2009 12:01:22 AM
Message: From application-wide exception handler: Symbol.Exceptions.OperationFailureException: SCAN_GetInterfaceParams
at Symbol.Barcode.InterfaceParams.GetInterfaceParams()
at Symbol.Barcode.InterfaceParams..ctor(Reader reader)
at Symbol.Barcode.Actions.Enable()
at HHS.frmFind.InitReader()
...so the additional log file entries were preventing the exception msg from getting logged.
UPDATE 4
Actions.Enable?
I was unfamiliar with this, and when I added "Actions." I got a choice between Symbol.Barcode.Actions and Symbol.Generic.Actions.
I chose the first first, but it has no "Enable" method. Adding it scolded me with, "An object reference is required for the non-static field, method, or property 'Symbol.Generic.Actions.Enable()'"
I then commented out the using that was added, entered "Actions." again, and this time chose Symbol.Generic.Actions (and got the same err msg for my troubles).
How can I use Actions.Enable()?
UPDATE 5
C.Evenhuis: by "some events require re-attaching each time they occur" do you mean this:
private void 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 StopRead()
{
// If we have a reader
if (this.barcodeReader != null)
{
// Flush (Cancel all pending reads)
this.barcodeReader.ReadNotify -= this.barcodeEventHandler;
this.barcodeReader.Actions.Flush();
}
}
...(barcodeReader.ReadNotify is attached in StartRead and detached in StopRead), or is more necessary?
I also have, in InitReader():
this.Activated += ReaderForm_Activated;
this.Deactivate += ReaderForm_Deactivate;
...which are implemented like so:
private void ReaderForm_Activated(object sender, EventArgs e)
{
// 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)
{
this.StopRead();
}
InitReader() is called from textBoxScan_GotFocus(); textBoxScan has the focus when the form displays.
UPDATE 6
As to "Explicitly Close() classes before you Dispose() them", I call Dispose on two things, Symbol.Barcode.Reader and Symbol.Barcode.ReaderData, and neither one allows a Close() call.
UPDATE 7
This statement from C. Evenhuis: "you can't have two (foreground) readers enabled" led me to try the following:
private void FrmDelivery_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
this.barcodeReader.Actions.Disable();
}
...which seems to have pretty much done the trick - I can open the Find form without a hang resulting in an eventual crash. I can scan into the Find form after having scanned into the Delivery form. The only (unrelated?) problem that I still see is that my Find form is still partially obscured for some reason...
Symbol Motorola Zebra is building on a legacy C++ library with a legacy .NET wrapper. There are quite some pitfalls (some events require re-attaching each time they occur, some classes require explicit Close() before you Dispose() them, etc).
As you may have found out, you can invoke members of the Symbol classes from multiple threads / forms, but you can't have two (foreground) readers enabled, and some properties can only be set if no background readers are enabled, and there is no way to determine whether there are background readers enabled (ie DataWedge).
At our company we chose to initialize the scanner in the Form.Activated event and deinitialize it in the Deactivated event. Then when scanning was required, a call to Actions.Enable() would do the trick. Setting reader properties is done in try catch blocks :(
Quite odd that your application crashes at GetInterfaceParams, I would expect Setting them to cause trouble. Try your application with the bare minimum; don't set the BeepTime or WaveFile properties.
I'm not familiar with this type of scanner, but I can imagine initreader will do something at a hardware level. It will probably try to open some port. Because the port is already open it fails.
You need to implement a singleton service for your scanner instead of addressing it directly in your form. Then you can initialize the reader once for the complete application and use it wherever you'd like.
This will be a lot more 'SOLID' and thus more maintainable.
I just added the feature where I can make my program the default-program for multiple music filetypes by following this question on Stackoverflow
It seemed to work fine, since all of the mp3 files etc has my icon on them in Explorer.
But when I tried starting one (I have handled the arguments just fine) the process itself starts (it shows up in Task Manager) but nothing happens. I even tried adding a Messagebox in the beginning of the "Window.Initialized"-event, but no messagebox came up.
What might be the cause of this problem? I have literally no idea what's wrong.
If you need code or anything, just ask for it since I don't know what to include in this question.
Thank you.
Here's the code for Window_Initialied
private void Window_Initialized(object sender, EventArgs e)
{
MessageBox.Show("asd");
HandleInstances(); // Checks if multiple instances of the program is running. Exits it if there's more than one instance (tried commenting this out, didn't work)
if (Properties.Settings.Default.HasRegisteredFiletypes == false) // Checks if theres a need to add the filetypes
AddExec();
StartWithMusic(Environment.GetCommandLineArgs().ToList()); // Here I call for the arguments. Checks if there are valid files in the arguments (.mp3, .flac etc)
SettingsLoadBGs.IsChecked = Properties.Settings.Default.LoadBGs;
// set accentcolor box
List<AccentColor> ac = new List<AccentColor>();
string userAccent = Mplayer.Properties.Settings.Default.Accent.ToLower();
foreach (Accent c in ThemeManager.DefaultAccents)
{
AccentColor acEnt = new AccentColor();
acEnt.Name = c.Name;
ac.Add(acEnt);
if (c.Name.ToLower() == userAccent)
ThemeManager.ChangeTheme(this, c, Theme.Dark);
}
ThemeManager.IsThemeChanged += new EventHandler<OnThemeChangedEventArgs>(ThemeChanged);
accentChooserBox.ItemsSource = ac;
}
I'm in the middle of adding new functionality to my winforms controls, and part of that requires that a variable that was once always used to now be optional (if it's null, get the data from a second source). I made some changes and ran my form, only to find out nothing was happening, even functionality that previously worked. Confused I stepped through the code and found out that my Winforms user control was throwing a NullReferenceException when it encountered my variable, but in the UI no errors were being thrown.
My setup is I have a UserControl with a combo box. When the user changes that combo box it loads a secondary UserControl in a panel the first control has. The second control is what is throwing the exception.
Here are the code paths:
private void cmbActionType_SelectedIndexChanged(object sender, EventArgs e)
{
if (_loading)
return;
// ActionType was changed, update the action.ActionType value
if (cmbActionType.SelectedItem != null)
{
if (cmbActionType.SelectedItem.ToString() == SETVALUE_OPTION)
_action.ActionType = ActionTypes.SetValue;
else if (cmbActionType.SelectedItem.ToString() == CHECKVALUE_OPTION)
_action.ActionType = ActionTypes.CheckValue;
else
_action.ActionType = ActionTypes.CustomAction;
}
RefreshActionPanel();
_editor.DataModified();
}
private void RefreshActionPanel()
{
// Control defaults
AnchorStyles styles = AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Top;
UserControl subControl = null;
// Clear the currently active control
pnlActionDetails.Controls.Clear();
// Determine what type of control to load in the panel
if (cmbActionType.SelectedItem != null && cmbCaseType.SelectedItem != null)
{
// SetValue or CheckValue actions
if (cmbActionType.SelectedItem.ToString() == CHECKVALUE_OPTION || cmbActionType.SelectedItem.ToString() == SETVALUE_OPTION)
{
if (_caseTypeMap.ContainsKey(cmbCaseType.SelectedItem.ToString()))
subControl = new SetCheckActionControl(_action, _editor, _caseTypeMap[cmbCaseType.SelectedItem.ToString()]);
}
// CustomAction action type
else
{
// Check if the requested case is a type or defined in a script
if (_caseTypeMap.ContainsKey(cmbCaseType.SelectedItem.ToString()))
{
subControl = new CustomActionControl(_action, _editor, _caseTypeMap[cmbCaseType.SelectedItem.ToString()]);
}
else if (_editor.ScriptDefinitions.Any(x => x.CaseName == cmbCaseType.SelectedItem.ToString()))
{
var definitions = _editor.ScriptDefinitions.Where(x => x.CaseName == cmbCaseType.SelectedItem.ToString()).ToList();
subControl = new CustomActionControl(_action, _editor, definitions);
}
}
}
if (subControl != null)
{
subControl.Anchor = styles;
subControl.Height = pnlActionDetails.Height;
subControl.Width = pnlActionDetails.Width;
pnlActionDetails.Controls.Add(subControl);
}
}
public CustomActionControl(TestAction action, fmEditor editor, IList<TcScriptDefinition> scriptDefinitions) : base(action, editor)
{
_loading = true;
InitializeComponent();
_scriptDefinitions = scriptDefinitions;
PopulateActionList();
SetupDataGrid();
_loading = false;
}
private void SetupDataGrid()
{
// Clear the current contents of the datagrid
grdParameters.Rows.Clear();
if (cmbAction.SelectedItem == null)
return;
// Retrieve the action code from the drop down
string actionCode = cmbAction.SelectedValue.ToString();
// Check if any paramters are available for this action
if (!_availableActionParameters.ContainsKey(actionCode))
return;
// Add a new row for each parameter available for this action
foreach (string param in _availableActionParameters[actionCode])
{
string display = param;
// Determine if the parameter has a display string
if (_formInstance.CodeDisplayMap.ContainsCode(param))
display = _formInstance.CodeDisplayMap.GetDisplayStringFromCode(param);
// Create the array for the row, with an empty string as the current value
string[] row = { display, string.Empty };
// Check if the current action uses this action code.
// If so, retrieve the value for this parameter and use it in the row
// Note: Case-INsensitive comparison must be performed here
if (_action.Attributes["action"].Equals(actionCode, StringComparison.CurrentCultureIgnoreCase))
if (_action.Attributes.ContainsKey(param))
row[1] = _action.Attributes[param];
grdParameters.Rows.Add(row);
}
}
The NullReferenceException is coming from the SetupDataGrid() method where _formInstance is being called. However, usually when an application encounters an unhandled exception the JIT system throws an error message saying such (and as you can see, there's no try/catch statements used unless I am blind).
Why does my winforms application show no signs of an exception occurring. I'd rather an unhandled exception message occur rather than nothing happening, as that makes it harder for users to know something critical went wrong (as opposed to it not responding to their commands)
Edit: To clarify since there seems to be some confusion, I do NOT care about breaking on this exception in visual studio when debugging. The fact of the matter is that the application should not be hiding unhandled exceptions, and my application should crash (or rather show the JIT message that an unhandled exception occurred), even when not in debug mode outside of visual studio.
This is not a debug time question but a production run time question. If this code throws an OutOfMemoryException for instance, I need it to not be silently ignored. Right now it is being ignored.
Go to Debug->Exceptions... (Ctrl-D, E if you are using default shortcuts) from your menu bar in Visual Studio and check the box for Thrown under Common Language Runtime Exceptions. This will cause your program to break on exceptions even if they are in a try/catch block. You can then do a step forward and see where the code is jumping to for the next instruction. That should bring you to the catch block that is hiding your exception.
It may be jumping in to .NET code for the catch, you can go to Debug->Options and Settings.. and turn on Enable .NET framework Source Stepping to see what it is jumping in to.
Here is a example of catching the unhandeled execptions in code
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
Application.Run(new Form1());
MessageBox.Show("0");
}
static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e)
{
MessageBox.Show("1");
}
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
throw new ArgumentNullException();
}
}
Click the button and 1 appears, the program should still run afterwards.
However as I said in my last comment, check that user-unhandeled is checked (maybe uncheck and recheck) in Debug->Exceptions first it may solve your initial issue..
They can be caught if you have a try/catch in your Main, or if you have a ThreadException handler. Also check out SetUnhandledExceptionMode.
Note that if they're caught in Main, your program will just exit silently. ThreadException can "catch" and ignore them.
EDIT: Since the debugger doesn't break when you uncheck the box for Thrown under Common Language Runtime Exceptions, it's being caught by the code for Windows Forms. This is not ideal, but a lot of the BCL does this. You don't need to worry about it catching OutOfMemoryException or anything like that; the BCL should only be catching exceptions that it expects (vexing exceptions).
To be clear, the exception is not "unhandled". It is handled by the BCL code.