Native Extensions for Microsoft Silverlight is a collection of COM automation based runtime libraries and Silverlight libraries which allow elevated trust 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 then 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 noticed 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 which control notification code we are interested in. 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 a demo of the application, click Silverlight remote control demo.