Memory Profiler Eating Up My Memory

I have a Windows Forms app that has a very long and complicated initialization process. As the release is approaching, today was my day to try and shoft things around in the init, get it loading faster. So on recommendation from a few sources, I downloaded a profiler – Jet Brains dotTrace. Install and first profile went well. However, as I started to make more changes and run more profiles, I noticed that there were no improvements in initialization time. If anything, things were getting worse. Task Manager helped pinpoint the culprit:

If the numbers are too small, that is 1,241,596 KB. Yikes. Compare that with the second and third-place contestants, FireFox 3 at 174,584 KB, Visual Studio 2005 at 144,940 KB.

This is what happened after I closed the profiler (see if you can guess when that happened):

And I thought that Firefox 2 was using a lot of memory. I know that these programs are complicated, but I find it hard to comprehend how a program is supposed to help you track the memory usage of the applications that you are debugging when it ends up gobbling down over 1.2GB of RAM all by itself and making the computer basically unusable.

Detecting Application Idle State in Windows Forms

On a recent project, I had the need to detect whether or not the application is idle, and if so, for how long has the idle state persisted. Idle in my case is defined as no mouse movement or keyboard activity when any of the forms of the application are in focus. If a different program is in focus, I define this as being an application-idle state (for my app), regardless of whether or not there is input activity from keyboard or mouse.

On researching the subject, I found several approaches. The main approach I have seen is to use the static Application.Idle event. This event fires whenever “application finishes processing and is about to enter the idle state” – In other words, whenever the application’s message queue is empty. The problem with this approach is that this event fires a lot, so much that it becomes impractical for tracking idle state the way that I need it (it doesn’t help that any Timer operating to track how long the idle state persists would set off Application.Idle, further complicating the situation).

The other approach that I have seen is to set up some Windows hooks to detect mouse and keyboard activity. I have zero experience operating with the Windows API, so thankfully, I found a post by Johan Danforth that gives some working code for doing exactly what I needed: Detecting Idle Time with Mouse and Keyboard Hooks. I integrated the code with my application and tested it out and it worked great.

There was one problem however: this code detects idle time for all applications. In other words, if your application is open but not in focus and you use your mouse or keyboard, the code changes your application status from Idle to Active. For my purposes (see definition if idle above) this is not good enough. So I inspected different properties of the System,Windows.Forms.Form class to see what could tell me whether or not a given form is active. The first candidates were Focused, TopLevel, TopMost and Visible, but none of these did the job. The property that ended up telling me exactly what I needed to know is ContainsFocus. This is a property of the Control class (from which Form inherits) and it “Gets a value indicating whether the control, or one of its child controls, currently has the input focus”. (Focused is not good enough, since it only returns true when the form itself has focus, but returns false when a child control contained within the form has focus).

I also needed to detect whether any of the secondary forms of my application had focus (since I could have more than one window open at a time, only one of which could have focus). Here is the code that I used:

private bool DoesApplicationHaveFocus() {
  bool hasFocus = false;
  if (ContainsFocus) {
    hasFocus = true;
  } else {
    FormCollection forms = Application.OpenForms;
    foreach (Form f in forms) {
      if (f != null && f.ContainsFocus) {
        hasFocus = true;
        break;
      }
    }
  }
  return hasFocus;
}

WYSIWYG Editing of HTML in a Windows Forms Control

In a WinForms project that I am working on right now, I have text stored in HTML format in the database. I need a way for novice users to be able to edit this text using a WYSIWYG interface.

The most obvious choice for this in the Windows.Forms control library that is part of the .Net 2.0/3.0 framework is the RichTextBox control. This control gives you a textbox that has functionality similar to the WordPad application found in the Windows OS. It can display formatted pretty well. Aside from the fact that you have to handle all formatting of text in code, RichTextBox it has one major shortcomings: It can only input/output plain text or RTF encoded text. If I wanted to use a RichTextBox control to edit HTML, I would need some way to translate from the source HTML (stored in the DB) to RTF (to be displayed in the RichTextBox) and then back to HTML (to be stored again in the DB). Although I found some components from Sautin Software that seem to do the job, they cost money that I would rather not spend, and add a layer of complexity to my code library that I would rather avoid.

I found a couple of controls that extend the RichTextBox in order to allow input of HTML: An extended RichTextBox to save and load “HTML lite” files by Oscar LondoƱo (Code Project – For .Net 1.1/VS 2003) and RichTextBox that Displays XHTML by Eric Voreis. Both of these controls extend the RichTextBox control in the Windows.Forms library so that it can translate on the fly between RTF and HTML code (so you can input HTML code, see it displayed in the RTB and export HTML code). However, both are old and only support a small subset of HTML tags (although this can be extended in the source, it required knowledge of how RTF works). Also, since they use a RichTextBox control for editing and display, the display is similar but not identical to what you would get using a WebBrowser.

The next method that I found for providing this type of error is HTML Editor by Carl Nolan (Microsoft Consulting Services). This control (written in 2003 for .Net 1.1) modifies a WebBrowser control to allow inline editing and display of HTML. It is professionally written, provides support for many HTML tags and does just about everything that I need (and is free). The one problem is that it is pre-.Net 2.0. It uses a WebBrowser control from before this control was included as part of the Windows.Forms library in .Net 2.0 and thus has to reference Win32 calls and perform other types of acrobatics in order to get the control to function properly. This matters to me because it decreases portability of the control (using Mono, for instance), and makes it harder for me to customize and edit.

WebBrowser-based HTML Editor in action

The control that I am using in the end employs the same general idea used in HTML Editor, but takes advantage of new features (like the native WebBrowser class) provided by the .Net 2.0/3.0 framework and and Visual Studio 2005. A Windows Forms based text editor with HTML output by Kevin DeLafield uses a WebBrowser control with modified functionality to allow WYSIWYG display and editing of HTML text. It provides all of the functionality that I am looking for and allows for easy modifications and customizations in Visual Studio 2005. I recommend that anyone in need of similar functionality take a look at this control.

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.

In Search of an Embedded DB for a Windows Forms Application

So I am in the middle of building a pretty substantial Windows Forms application in .Net 2.0/C#, which will rely very heavily on database integration. Currently development is proceeding using Sql Server Express 2005 for the database server. It is a very robust product that supports anything that you can do on the full edition of SQL Server, and is freely distributable. Stored procedures, triggers, the works.

However, when making the first internal release intended to be installed by other people, I ran into some problems, specifically related to the way that SQL Express works. As it is really the same thing as the full version of SQL Server (with limits put on DB size and other licensing issues), it requires a big download (around 35mb), large db file footprint (around 20mb) separate installation, and runs as a service on the client machine. Though the install can be packaged as part of your overall distribution and set to install “silently”, it is still an issue that requires ongoing support and trouble-shooting. Additionally, you can sometimes run into problems with the SQL Express service, permissions, problems attaching the database to the server, etc. It is a robust solution, but the potential problems involved in installing SQL Express on thousands of client machines and getting it to run flawlessly all the time is enough to give me pause.
Continue reading