Friday, December 03, 2004 11:45 PM
MessageBoxOptions enum demystified
What the heck?
Wondered what the MessageBoxOptions enum's function actually is? When using the MessageBox.Show static method to show a message box on the screen there is actually a last parameter (typically omitted since it's not obligatory at all) called MessageBoxOptions that can be used to allow communication of a background service (Windows Service) with the active desktop through means of the csrss.exe. To be honest I was quite surprised to see that this is actually available in the .NET Framework and I'm using it now for debugging reasons only. In cases where you want to notify the interactive desktop user of some condition inside the Windows service this can be rather helpful. In production, messaging through means of the event log, WMI events, performance counters, MSMQ, etc is far better for manageability reasons.
How does it work?
Create a Windows Service project in Visual Studio .NET. I assume you've done this already; if not, I'll repeat the basic steps since it's one of my favorite .NET development horsepower exposure topics :-). Go to VS.NET, select the language of your choice, choose the Windows Service project and continue. You'll see a designer surface that actually is used to design and implement the Windows Service you're going to develop. On there you can add components such as a timer (use the Components timer, not the WinForms timer!!!), a message queue, etc. Click the surface and go to the properties to give the service a good name (in my case MessageSvc) and dive into the code behind the designer surface. As you'll see, two significant methods are living in there: the OnStart method and the OnStop method which are respectively called during service startup and service shutdown. Over there, you'll typically add code to start a background thread (or threadpool) in order to receive and handle incoming user requests that the service should support (e.g. install a poller on an MSMQ queue, listen to a socket, use .NET Remoting channels, play a watchdog for another (series of) process(es), play agent, etc).
- Create the Windows Service project
- Give the service the name MessageSvc
- Add a timer (from the components section in the toolbox) to the designer surface but disable it (enabled = false) and set the Interval to 10000 (= 10 seconds)
- Double-click on the timer to switch to the code view and implement the default event for the timer control (there is only one event, which is the Elapsed event)
- Add the following code over there:
private void timer1_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
MessageBox.Show("Time now: " + DateTime.Now.ToString(), "Some demo", MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1, MessageBoxOptions.ServiceNotification);
- This will send a message with the current time to the interactive desktop on the console of the system
- In the code, add
timer1.Enabled = true
to the OnStart method, and
timer1.Enabled = false;
to the OnStop method.
- Switch back to the design view, right-click and choose Add Installer
- You'll find a serviceInstaller1 control now on the designer surface of a separate file called "ProjectInstaller.cs".Put the StartType to Automatic and check the ServiceName property (should match the name chosen earlier, i.e. "MessageSvc")
- Beside of this control there should be another control responsible to install the service process (serviceProcessInstaller1). Choose as the account LocalService over there
Now compile the project and open up a Visual Studio .NET Command Prompt. Over there, cd into the bin\debug folder of your solution and install the service by running the installutil.exe tool against the file:
(replace the file name of course)
Now start the service using net start MessageSvc and you should see a message popping up every 10 seconds with the current time. Annoying but it shows the basic functionality. Stop the service again using net stop MessageSvc. And don't forget to uninstall it again if not needed anymore (I guess you don't want to run my sample on your production box :-)) using installutil -u.
- Keep in mind the MessageBox.Show method waits till the the user confirms the message by clicking OK. So, calls to the MessageBox.Show will be queued if the user does not respond to the message.
- Only use this when absolutely needed, for example to show a message about a real rare event that requires immediate action. However, in such a case a WMI event captured by MOM or so would be the better choice.
- You can also use MessageBoxOptions.DefaultDesktopOnly which will require an "active interactive session" on the console to send the message to. The MessageBoxOptions.ServiceNotification will send the message to the "logon desktop" as well (so no need to have a user being logged on at the console). The tiny message "At least one service or driver could not be started during system startup. Refer to the event log for more information." (blahblah) in for example Windows Server 2003 (a mesage that you don't like to see often by the way) is actually what you can expect as the behavior from the MessageBoxOptions.ServiceNotification option.
| Digg It
Filed under: Microsoft