Skip to main content

SystemEvents issues

SystemEvents is a class that allows users to receive events that are system-wide. These events range from system time changing (due to daylight savings or time sync or manual time changes) to SessionEnding to LowBattery, to FontsInstalled events, etc.

There are many issues with this class
1- It does not work in a Windows Service, unless the service interacts with the desktop (which is an XP feature only). Vista and Windows 7 has an awkward support to say the least for services that interact with the windows desktop. As far as I'm concerned, it is not supported.
2- If you call any SystemEvent.XYZ += OnXYZ;, this ends up creating a hidden window. So what's the problem? if you have any WCF objects that register themselves (using WCF's ServiceHost) in the same thread as the one that called SystemEvents, then all subsequent calls to the WCF services will be serialized on that thread. Most likely that thread is the main UI thread for your application. This results in nasty deadlocks that are very difficult to debug and isolate.

So what's the solution?
I tried various methods including the Microsoft's suggested way to handle this issue http://msdn.microsoft.com/en-us/library/microsoft.win32.systemevents_events.aspx but SystemEvents seems to have a mind of its own and you will fix #1 above but you will still end up with #2.

I decided to write my own System Events class as  it is simple and straight forward.
I was mainly focused on the TimeChanged event but you can add other events as needed

public class SystemEventsEx : NativeWindow
{
   public event EventHandler TimeChanged = null;


   public SystemEventsEx()
   {
       CreateParams cp = new CreateParams();
       cp.Caption = "WindowsMessageTarget";
       cp.Width = 0;
       cp.Height = 0;
       cp.X = 0;
       cp.Y = 0;
       cp.Parent = IntPtr.Zero;
       CreateHandle(cp);
     }


   protected override void WndProc(ref Message m)
   {
      if (m.Msg == WindowsMessages.WmTimeChanged)
      {
          TimeChanged((object)null, (EventArgs)null);
      }
      base.WndProc(ref m);
   }
}

Make a stsatic class that can host the SystemEvents instance and allow subscriptions to systm events as follows:

public static class MyApplication
{
   private static SystemEventsEx _systemEvents = null;


   public static SystemEventsEx SystemEvents
  {    get { return _systemEvents; } }


   public static EnableSystemEvents()
   {
       Thread t = new Thread(OnEnableSystemEvents);  
       t.IsBackground = true;
       t.Start();
   }


   private static void OnEnableSystemEvents()
   {
      _systemEvents = new SystemEventsEx();
      Application.Run();
   }
}

In you main.cs
you can do the following:
[STAThread]
public static void Main(string[] args)
{
   . . .
    MyApplication.EnableSystemEvents();
   . . .
}

Comments

Popular posts from this blog

Visual Studio 2010 was released yesterday

Unfortunately, I have just checked the MSDNAA site and they still do not have the release version of Visual Studio 2010. They only have an old Beta2. I would recommend that if you do not have access to Visual Studio 2010 through other means, that you keep an eye on the MSDNAA web site and see if VS2010 becomes available. If and when it becomes available, I would not recommend that you install it while you are finishing CS 503. Download it and save it somewhere and when the course is done, you can knock yourself out :)

Wave Undo

To implement Undo, the simplest way is to use a MemoryStream object in your WaveDisplayForm (MDI Child) and simply serialize the Wave (which should be marked as [Serializable] to the stream and hold on to the stream object. private MemoryStream _undoStream = new MemoryStream(); private bool _canUndo = false; public void SaveForUndo() {      BinaryFormatter bf = new BinaryFormatter();      bf.Serialize(_undoStream, wave);      _undoStream.Flush();      // This rewinds the stream so that when it is used for deserialization, it's ready to use,     // otherwise, the deserialization will start deserializing from the end of the stream and would fail.      _undoStream.Position = 0;      _canUndo = true; }   public void Undo() {      BinaryFormatter bf = new BinaryFormatter();      ...

My Plans for this Blog

I intend to post new things I learn or run into or that come to mind on at least a weekly basis. Sometimes may be daily. I'm planning on starting after the course ends so I do disturb the peace of the final project. You have options to unsubscribe yourself from this Blog site completely and you are welcome to stay as you fell like it. It's all up to you. I also would be open and willing to respond to those tough questions you may run into assuming the volume of questions would be manageable...... Knowing you guys, I think it will be very quite in this neighborhood.