Native Extensions for Microsoft Silverlight is a collection of COM automation based runtime libraries and Silverlight libraries which allow elevated trusted out of browser applications to utilize windows platform feature. For example, you can build applications which use Sensor API, Speech API, react to remote control, integrate with windows 7 taskbar or listen to windows messages sent to the host window. In this post, I will build a simple slideshow application to demonstrate some of the capabilities of the library.
The application allows users to choose images from their computer and control the slideshow with remote control as well as with taskbar buttons. Building the slideshow itself is very easy so I will briefly explain how it works: When the user selects pictures a timer is started. When the timer tick event is fired it fades out current image, switches to the next image and fades it in. The user is also able to stop the slideshow and manually switch between the images. The buttons can be also triggered with remote control and taskbar buttons.
Responding to remote control buttons
According to remote control documentation to respond to remote control you need to listen to various windows messages. For example, let’s implement pause/resume when
APPCOMMAND_MEDIA_PAUSE or APPCOMMAND_MEDIA_PLAY commands are received. To interpret these commands we need to catch
WM_APPCOMMAND message.
public MainPage()
{
InitializeComponent();
WindowMessageInterceptor.Current.WindowMessage += MessageReceived;
WindowMessageInterceptor.Current.AddMessageIntercept(NativeMethods.WM_APPCOMMAND);
}
As you have probably guessed MessageReceived is a method which will be called when the host window receives
WM_APPCOMMAND message. The handler will also receive message details such as wParam and
lParam. To get the command which triggered the message we need to process
lParam by calling GET_APPCOMMAND_LPARAM Macro. The macro is defined in
Winuser.h as:
#define GET_APPCOMMAND_LPARAM(lParam) ((short)(HIWORD(lParam) & ~FAPPCOMMAND_MASK))
HIWORD is another macro defined in Windef.h as:
#define HIWORD(l) ((WORD)((((DWORD_PTR)(l)) >> 16) & 0xffff))
The corresponding code in C# looks like this:
public static int GET_APPCOMMAND_LPARAM(int lParam)
{
return (short)(HIWORD(lParam) & ~FAPPCOMMAND_MASK);
}
private static int HIWORD(int lParam)
{
return ((lParam >> 16) & 0xffff);
}
We are now ready to implement the MessageReceived handler:
private void MessageReceived(object sender, WindowMessageEventArgs e)
{
if (e.Message == NativeMethods.WM_APPCOMMAND)
{
int cmd = NativeMethods.GET_APPCOMMAND_LPARAM(e.lParam);
switch (cmd)
{
case NativeMethods.APPCOMMAND_MEDIA_PLAY:
ResumeSlideShow();
break;
case NativeMethods.APPCOMMAND_MEDIA_PAUSE:
PauseSlideShow();
break;
}
}
}
Let’s add support for navigating between the images using left and right buttons on the controller. These buttons don’t generate
WM_APPCOMMAND message. Instead they trigger WM_KEYDOWN message which Silverlight supports out of the box. This means that to respond to these
buttons we need to simply respond to KeyDown event:
private void SlideShowKeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Left)
{
PreviousImage();
}
if (e.Key == Key.Right)
{
NextImage();
}
}
Adding support for taskbar buttons
The first step in adding support for taskbar buttons is to add the actual buttons. First we create the buttons and than instruct the taskbar to show them:
private void CreateTaskbarButtons()
{
for (int i = 0; i < 4; i++)
{
var thumbbarButton = TaskbarButton.Current.CreateThumbbarButton((uint)(i + 1));
thumbbarButton.Flags = THUMBBUTTONFLAGS.THBF_ENABLED;
thumbbarButton.ImageDataType = ButtonImageDataType.PNG;
var resourceInfo = Application.GetResourceStream(new Uri(
string.Format("images/{0}.png", i), UriKind.Relative));
using (var br = new BinaryReader(resourceInfo.Stream))
{
thumbbarButton.Image = br.ReadBytes((int)resourceInfo.Stream.Length);
}
taskbarButtons.Add(thumbbarButton);
}
taskbarButtons[0].Tooltip = "First Image";
taskbarButtons[1].Tooltip = "Previous Image";
taskbarButtons[2].Tooltip = "Next Image";
taskbarButtons[3].Tooltip = "Last Image";
TaskbarButton.Current.ShowThumbbarButtons();
}
You have probably notices that the code snippet is creating buttons but there are no event handlers to respond when they are clicked. Instead we need to use
WindowMessageInterceptor class again and subscribe to CommandMessage event. The event is raised in response to
WM_COMMAND message which is generated when a taskbar button is clicked. Apart from subscribing to
the event, we need to call the
AddCommandMessageIntercept method and specify in which control notification code we are interested it. This way the event will be raised only for that particular notification code. In
the case of taskbar buttons, the notification code is
THBN_CLICKED.
WindowMessageInterceptor.Current.CommandMessage += CommandMessage;
WindowMessageInterceptor.Current.AddCommandMessageIntercept(NativeMethods.THBN_CLICKED);
When the event handler is called, it will receive an instance of CommandMessageEventArgs class specifying
the notification code and control identifier. The control identifier corresponds to the
ButtonID we passed to the CreateThumbbarButton method when we created the buttons. This way we can identify which button caused the event to fire.
private void CommandMessage(object sender, CommandMessageEventArgs e)
{
if (e.NotifyCode != NativeMethods.THBN_CLICKED)
{
return;
}
switch (e.ControlID)
{
case 1:
FirstImage();
break;
case 2:
PreviousImage();
break;
case 3:
NextImage();
break;
case 4:
LastImage();
break;
}
}
To view demo of the application,
click at Silverlight remote control demo.