Mark Gilbert's Blog

Science and technology, served light and fluffy.

SSMS Scripter Internals Part 3 of 3: “Making a Splash”

In the previous part of this series I looked at the project settings and code components that defined the Scripter as an SSMS Plug-in.  In this third and final piece, I’ll look at the splash screen used by the Scripter, and how threading was used to make it look pretty.

Because of the way that the Scripter digs into the source database when it first boots up, databases with a large number of objects (stored procedures, views, or UDFs) can take more than a few seconds to load.  Instead of just appearing to doing nothing except churn, I added a simple splash screen that appears before the main form is instantiated.

My first splash screen had a single line of text.  As a result, it was easy to miss it on screen, since it blended in well with the half-dozen other windows that I regularly have open.  I wanted to make it stand out more, and I thought a simple animated GIF would be the best way.  I found a GIF on the web that looked similar to the moving circle icons that Microsoft seems to have incorporated into all of their most recent applications (SQL Reporting Services, IE 7, etc.).  It was large enough, and animated enough, to draw the user’s eye to the splash screen, and specifically my one line of text encouraging them to be patient (and not give in to the Dark Side of the Force).

The splash screen is opened from the Invoke method of the ScripterMenuItem class.  Originally I simply instantiated the form as a dialog, and closed it when the SSMSScriptor form finished initializing.  This caused the splash screen to open just fine, but the animation wouldn’t show because the splash screen never got a message to repaint itself.

I had first considered setting a timer to go off every quarter second or so, and force the dialog to repaint itself, but that seemed like a bit of a hack.  Instead, I opted to instantiate the form in its own thread and then kill it when the main form finished loading.

To do this, I needed to add the System.Threading namespace to my list of imports in the ScripterMenuItem class.  Then, I created three local private variables: m_tiSplashScreen, m_frmScripter, and m_frmSplashScreen.  The second one was declared WithEvents so I could declare a public ScripterMenuItem method called ScripterLoadedEventHandler that handles, well, the ScripterLoaded event of the SSMSScriptor object (a custom event).

The following is the startup sequence of events:

  • The ScripterMenuItem.Invoke method creates a new thread (stored in m_tiSplashScreen), and passes it the address of a private method of ScripterMenuItem called OpenSplashScreen. This private method instantiates the local private variable m_frmSplashScreen, and opens it as a dialog. I found that starting it as a separate form caused it to open, and then immediately close back down.
  • The Invoke method then starts the new thread, which causes the splash screen to actually be displayed to the user.
  • Finally the Invoke method creates the new SSMSScriptor form, and opens it.
  • The Load event handler of SSMSScriptor does its normal startup, and at the very end raises the ScripterLoaded event.
  • The ScripterMenuItem captures the ScripterLoaded event, and kills the splash screen thread (if it is still active).

Forcing the splash screen to run using a thread separate from the main program allowed it to refresh itself and show the animation properly.

December 26, 2006 Posted by | SQL Server, Tools and Toys | Comments Off on SSMS Scripter Internals Part 3 of 3: “Making a Splash”