Global Application Error Handling in Windows Forms Applications

In my current project, I would like to log all Windows Forms errors, including those that are not caught explicitly. Lacking a built-in method (like Application_Error in the Global.asax file of an ASP.net application), I needed another way to easily catch all errors. After a bit of searching, I found a solution by Craig Andera: WinForms Catch-All Exception Handling. Here is the short version:

In the main entry point for your application (found by default in the Progrsm.cs file, Main() method), add a listener for the Application.ThreadException event.

[STAThread] 
static void Main() {
  Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
  Application.Run(new Form1());
}

private static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e) {
  // Handle Exception
}

This should allow you to catch all Exceptions in your application that were not caught at the source.

Cannot Access a Disposed Object

In a Windows Forms application that I am working on, I had the following scenario: while the main form (Main.cs) is loading, I prompt the user to prove their credentials. If they are unable to do so, the form is closed (using this.close) and application execution is halted.

The problem is, when I first tried this, I an exception was thrown in Program.cs on the following line:

Application.Run(new Main());

The exception was of type System.ObjectDisposedException, and the accompanying message was “Cannot access a disposed object”.

What happened? According to the official documentation, the method System.Windows.Forms.Application.Run(Form) has the following purpose: “Begins running a standard application message loop on the current thread, and makes the specified form visible.” When this line of code is called, it first instantiates a new instance of the given Windows.Form implementation (in my case, Main.cs) and after it is instantiated, sets the Form.Visible parameter to true, thereby showing the form. In my case, during the instantiation of the form, the Close() method on the form was called, which disposes the Forms object. So when Program.cs attempts to set Main.Visible = true, Main is already disposed and the above error is thrown.

What is the workaround? I can think of two ways off the top of my head (the first one is the one that I ultimately used). Can you think of any others?

  1. Substitute the line in Program.cs with the following. Here the Main class is instantiated first, and only if it is still in existence and not disposed will Application.Run be called. Thus, if Main is closed during instantiation, Application.Run will never be called and the application will close on its own.
Main main = new Main();
if (main != null && !main.IsDisposed) {
  Application.Run(main);
}
  1. Do not call the user authentication code during the instantiation of the main Form of the application. Instead, call it in some event (like Activate) that is tied directly to the creation of the Form, but is not part of the initial instantiation code. In this case the class will instantiate, Application.Run will execute, and only after will the user authentication (and possible subsequent disposal of the form and exit from the application) take place.

.Net Encryption Simplified

Most of the projects that I work on require encryption of some form. Usually Symmetric (the kind where you can use the same password to both encrypt and decrypt), but sometimes asymmetric as well (where you encrypt with one password and decrypt with another). the .Net Framework has rich support for many different types of encryption algorithms, of varying methods and strengths, giving tons of options over how to run an exact implementation. However, one look at the System.Security.Cryptography namespace in the framework can end up leaving the novice user scratching his or her head over how exactly to proceed. Even individual implementation examples found on MSDN regarding individual algorithms are complicated pieces of code. Despite the wealth of code relating to this topic in the Framework, there is no one method (as far as I know) where you can simply put in data and a key, and receive encrypted text in response.
Continue reading

Visual Studio 2005 Add-Ins and Tools That I Use

I am right now in the middle (about 20% and 18K lines of code through) a pretty substantial Windows Forms project using Visual Studio 2005 (C#). Here are some of the add-ins that I have been using (ranked in order of essential to useful):
Continue reading

Porting .Net Assemblies to Mono using MoMA

For those who have not heard about it, Mono is a platform designed to allow porting of .Net-based applications to nearly every computing platform available (including Linux and Mac). It is open-source (sponsored by Novell) and is an essential tool for any developer who wishes to run .Net code on a non-Windows OS.

I am right now in the middle of a Desktop project being written with VS.net 2005, C# and Windows Forms technology. The powers-that-be (ie: the clients) have inquired to the feasibility of potentially porting over the code to Mac or Linux. My answer has been that if it is possible, we will have to use Mono to do it, but I cannot say anything more about its compatibility until more of the programming work is completed.

The process of porting over a completed .Net Assembly to Mono just got a bit easier. A tool called MoMA (Mono Migration Analyzer) has been released (written by Jonathan Pobst) that will do the following: given any .Net assembly (.dll or .exe file) it will go through the file and report back any potential issues that may arise using the assembly with Mono (most likely a .Net 2.0 feature that has not yet been implemented, or a calls to Win32 APIs that are not documented in the .Net API). Definitely a very helpful tool in debugging a .Net aseembly that refuses to compile in Mono.

Miguel de Icaza gives a more thorough step-by-step guide and review of his experiences using MoMA (though it doesn’t seem to be too complicated).

Error when sending Html Mail from ASP.net WebApp

On an ASP.net site (1.1), I was trying to send an email message using good old SmtpMail.Send(MailMessage message). When I did so, I got the following message “could not access CDO.message object“. After some Googling, I tried out all of the different security/smtp/relary/permissions related suggestions (most can be found on the systemwebmail.com site, a very handy reference if you have some questions regarding use of the System.Web.Mail library in ASP.net 1.1). Still not working. I checked the InnerException. It looked something like this:

InnerException: {“Unknown Error” }
Message: “Exception has been thrown by the target of an invocation.”
Source: “mscorlib”
StackTrace:
” at System.RuntimeType.InvokeDispMethod(String name, BindingFlags invokeAttr, Object target, Object[] args, Boolean[] byrefModifiers, Int32 culture, String[] namedParameters)\r\n
at System.RuntimeType.InvokeMember(String name, BindingFlags invokeAttr, Binder binder, Object target, Object[] args, ParameterModifier[] modifiers, CultureInfo culture, String[] namedParameters)\r\n
at System.Type.InvokeMember(String name, BindingFlags invokeAttr, Binder binder, Object target, Object[] args)\r\n
at System.Web.Mail.LateBoundAccessHelper.SetProp(Type type, Object obj, String propName, Object propValue)\r\n
at System.Web.Mail.LateBoundAccessHelper.SetProp(Object obj, String propName, Object propValue)”

But nothing apparently wrong there. The one weird thing that I could find is that if I set MailMessage.BodyFormat = MailFormat.Html, it would not work. If I set it to MailFormat.Text, it would work fine. Very suspicious.

In the end, the following solution worked for me. It was posted by Kyle Parker on the DotNetNuke forums:

  1. Close Visual Studio
  2. Open a Command Window
  3. regsvr32 cdosys.dll /u
  4. iisreset /restart
  5. regsvr32 cdosys.dll
  6. resume work in VS

After unregistering and reregistering this DLL, suddenly I was able to send Html mail again from my site. Kyle reported on his post that this only worked as a temporary solution. It is working for me so far.

Anyone know why this happened? Some other program messed up the dll that handles Html mail?