Presentation Mode in Vista

I was at a customer the other day, presenting on .NET 3.0, and the desktop background image on my computer is a picture of my son holding our dog. I should have changed the background prior to the demo, but I was running late and forgot.

It turns out that Vista has a feature to address this scenario. James Senior has a good overview of using Presentation Mode with Vista. When you go to the Mobility Center, you can configure settings for presentation mode including:

  • Turn Presentation mode on/off
  • Enable/Disable screensaver
  • Adjust volume of my computer when presenting
  • Show a specific wallpaper - so I can show the corporate brand instead of my holiday snaps!
  • Specify which currently connected display device to send the presentation video signal to

Cool. However, now I want to figure out how to extend this. For instance, I present a LOT from Vista using a virtualized guest OS such as Windows 2003 R2, and I do this with Virtual Server 2005 SP1 Beta 2 (go download it for free, it rocks) running on Vista as the host. I always have to remember to run a batch file that turns off unused services prior to running a virtual guest to provide enough RAM. It would be great to have a tray application that would remember to do a few more tasks when Vista goes into presentation mode.

It turns out that this is not all that hard to do.

The SHQueryUserNotificationState shell function allows you to query the user's state, receiving back a QUERY_USER_NOTIFICATION_STATE enumeration. The QUERY_USER_NOTIFICATION_STATE enumeration contains the following members:

typedef enum tagQUERY_USER_NOTIFICATION_STATE {

    QUNS_NOT_PRESENT = 1,

    QUNS_BUSY = 2,

    QUNS_RUNNING_D3D_FULL_SCREEN = 3,

    QUNS_PRESENTATION_MODE = 4,

    QUNS_ACCEPTS_NOTIFICATIONS = 5

} QUERY_USER_NOTIFICATION_STATE;

 

You can see that a value of 4 indicates that you are now in presentation mode. OK, so you can query the current user state, but how do you register for a notification? I certainly don't want to have to call this thing in a loop!

The docs for SHQueryUserNotificationState indicate that top-level windows will receive a WM_SETTINGCHANGE message when the user turns presentation settings on or off. That just means that you need to figure out a way to receive WM_SETTINGCHANGE messages, right? Easy enough, just override the WndProc function in a Windows Form and you are cooking.

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Text;

using System.Windows.Forms;

using System.Runtime.InteropServices;

 

namespace VistaUtilities

{

public partial class PresentationModeManager : Form

{

public readonly int WM_SETTINGCHANGE = 0x1A;

public readonly int QUNS_PRESENTATION_MODE = 0x04;

 

[DllImport("shell32.dll", CharSet = CharSet.Auto)]

public static extern int SHQueryUserNotificationState(out int qns);

 

public PresentationModeManager()

{

InitializeComponent();

}

 

protected override void WndProc(ref Message m)

{

base.WndProc(ref m);

if (m.Msg == WM_SETTINGCHANGE)

{

int state;

SHQueryUserNotificationState(out state);

if (state == QUNS_PRESENTATION_MODE)

{

Console.WriteLine("Presentation mode!");

}

}

}

}

}

The result is the ability to receive a notification when the user enters or exits presentation mode, allowing your application to react accordingly.