I have a context menu option that makes screenshots:
trayMenu.MenuItems.Add("Make a screenshot", makeScreenShot);
private void makeScreenShot(object sender, EventArgs e)
{
Screenshot currentScreenshot = new Screenshot();
}
And in the Screenshot class I have this commands:
Clipboard.Clear();
Clipboard.SetImage(screenshot);
And everything is OK when I am using this context option, BUT I also use a special .dll that helps me to make some shortcut combinations. One of these combinations has the same event handler.
HotKeysManager manager = new HotKeysManager();
manager.AddHotKey(new HotKeyCombination(new Keys[] { Keys.LControlKey, Keys.E }, makeScreenShot));
private void makeScreenShot()
{
Screenshot screenshot = new Screenshot();
}
The problem is, when I am trying to set an image in the clipboard, using the shortcut combination, it causes System.Threading.ThreadStateException.
The exception throws here: Clipboard.Clear();
Exception description:
Exception of type "System.Threading.ThreadStateException" appeared in System.Windows.Forms.dll, but was not handled in user code
More information: The current thread must be specified as a single-threaded stream container (STA), that calls OLE became possible. Check that your Main function is marked attribute STAThreadAttribute.
If this exception handler is available, program execution can be continued safely.
Related
I am trying to understand how a C# program handles an unhandled Exception.
I am doing my testing in a windows forms project, If the answer is different in other project types, please let me know.
I am running the program from the .exe file and not from the visual studio debugger.
Code:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
//timer1.Interval = 10000
private void timer1_Tick(object sender, EventArgs e)
{
//throw new Exception(Thread.CurrentThread.ManagedThreadId.ToString() + " This is an exception");
}
}
static class Program
{
static Form1 newForm;
static void Main()
{
Thread FormThread = new Thread(NewForm);
FormThread.Start();
Thread.Sleep(5000);
//throw new Exception(Thread.CurrentThread.ManagedThreadId.ToString() + " This is an exception");
}
static void NewForm()
{
newForm = new Form1();
Application.Run(newForm);
}
}
My question is what will be the windows response for an unhandled Exception in a C# program?
in the above example:
If the exception is thrown from the timer1_Tick function (by deleting the comment prefix) I am getting the following message:
If the exception is thrown from the Main function (by deleting the comment prefix) I am getting the following message:
why I am getting 2 different messages and how the windows/program "choose" which message to pop.
Thank you.
In a WinForms application, event handlers are invoked by the WindowsFormsSynchronizationContext. When an event handler throws an unhandled exception, the context handles it by displaying the first error dialog. At that point the synchronization context (which is simply a message pump) is still running and it could still proceed handling other events, so you are given a choice.
The Main method, in contrast, is invoked by the operating system itself, to start the application. If there is an unhandled exception there, WIndows has no option but to terminate the application, and it shows the second dialog to inform you of this.
I'm developing a Windows Forms App, a connector between a callCenter and a CRM and I'm clogged with an unhandled exception which I can't understand or either solve.
My App has:
MainForm with some controls and a FlowControll Pannel which may or may not show a collection of SearchForms - OK
SearchForm - basically a DataGridView with clickable cells - depending on the column index, the click will perform different operations - OK
DialForm - loads as consequence of clicking a cell on my SearchForm and allows to i) Cancel (closes the form OK); ii) dial a number -PROBLEM - very frustrating
When I click to dial, the app correctly makes the phoneCall trough my callCenter, but the very next line of code (Dispose() upon the DialForm) generates an unhandled exception of type 'Safe Handle has been closed', reportedly with DangerousAddRef(Boolean& success).
The relevant methods:
///
/// DialForm Method - upon clicking «Dial Number» Button
///
private void dialButton_Click(object sender, EventArgs e)
{
//
// Piece of code to manage closing with DialFormCloseEventArgs
//
DialFormCloseEventArgs args = new DialFormCloseEventArgs();
args.toClose = this;
EventHandler<DialFormCloseEventArgs> eh = father.Search_CloseDialForm;
this.BeginInvoke(eh, new object[] { sender, args });
}
///
/// SearchForm Method - EventHandler to close DialForm and make call
///
public void Search_CloseDialForm(object sender, DialFormCloseEventArgs e)
{
string numberToDial = e.toClose.numberToDial.Text;
e.toClose.Dispose();
this.rePositionMainForm();
using (ConectorCTI.ConectorCTI ctiws = new ConectorCTI.ConectorCTI())
{
ctiws.Timeout = 180000;
// Synchronous Call
//ctiws.Dial(this.userLoginName, numberToDial, "");
// Assynchronous Call
ctiws.DialAsync(this.userLoginName, numberToDial, "");
}
}
I also show my App with textual descriptions so you can actually «see it»
Probably need to wait for the async task to complete before disposing of the object. Something like
using (ConectorCTI.ConectorCTI ctiws = new ConectorCTI.ConectorCTI())
{
var task = ctiws.DialAsync(this.userLoginName, numberToDial, "");
await task;
}
I have used MouseKeyboardActivityMonitor to set some limitations for user activities for example disable mouse.
www.codeproject.com/Articles/7294/Processing-Global-Mouse-and-Keyboard-Hooks-in-C
I have these code in my form
public partial class MyForm:Form
{
KeyboardHookListener kl;
MouseHookListener ml;
MyForm:Form()
{
ml = new MouseHookListener( new GlobalHooker());
ml.Enabled=true;
}
private void MyForm_Load
{
ml.MouseDownExt += ml_MouseDownExt;
// And same thing for Click or ...
}
private void ml_MouseDownExt( object sender,MouseEventExtArgs e)
{
e.Handled= true;
// I have got hard disk serial number here
string sn = HardDisk.Serial;
}
}
And code of HardDisk.Serial
ManagementObjectSearcher s= new ManagementObjectSearcher(" SELECT *...");
foreach( var wmi in s.Get())
{
}
I get error when I click on MyForm .
When I built my solution and run it manually
I get this error
The application called an interface that was Marshalled for different thread
Stack:
at system.management.MangementException.ThrowWithExtendedInfo( Exception e)
at system.management.MangementObjectSearcher.Get()
at HardDisk.Get_serial()
at ml_MouseDownExt( object sender,MouseEventExtArgs e)
at MouseKeyboardActivityMonitor.MouseHookListener.InvokeMouseEventHandlerExt(EventHandler'1 handler,MouseEventExtArgs e)
But when I run my solution with visual studio an exception will throw at HardDisk.serial
at s.Get line , I get this
Error:
Managed debugging assistant ' DisconnectedContext'
Has detected a problem in 'my app Name.exe'
Transition into com context 0xa4206 for this runtime callable wrapper failed with following error :
an outgoing call can't be made since the application is dispatching an input asynchronous call
It obvious that two error is from MangementObjectSearcher class.I get serial number in another place in MyForm .errors just occurres when get serial in ml_MouseDownExt method or other method that has been added to events of GlobalHooker .I have seen msdn. In inheritance hierarchy of MangementObjectSearcher I see System.MarshalByRefObject
https://msdn.microsoft.com/en-us/library/system.management.managementobjectsearcher(v=vs.110).aspx
I don't know that it is related to these errors or not
How should I avoid these errors?
Your hook callback isn't being raised on the right thread. And that's just the first problem. Wrap it in a BeginInvoke and all will be well:
private void ml_MouseDownExt( object sender,MouseEventExtArgs e)
{
e.Handled= true;
var wrongThread = new Action(()=>
{
// I have got hard disk serial number here
string sn = HardDisk.Serial;
//put anything else you were planning on doing with sn here
}
BeginInvoke(wrongThread, null);
}
The second problem is that you're trying to interact with a COM object in the handler for a global hook. BeginInvoke should get around that nicely by delaying it for a few microseconds.
Don't forget to make sure Dispose gets called on that global hook. Closing the app isn't enough unless you like rebooting often.
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'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.