We (the WPF test team) are looking for several engineers, so I wanted to use the blog to point to the available positions in the team and give you a brief outline of the opportunities and responsibilities associated with each position.
Software Development Engineer in Test
(see official job posting)
As a SDET on the team you'll be responsible for ensuring the high quality of the WPF platform, by being the first and most critical customer of the platform, by being the first application developer using the new features introduced in WPF.
An accomplished SDET on our team is...
- a world-class CS engineer;
- an expert application developer, passionate about UI;
- a feature expert, with deep knowledge of specific parts of the WPF stack (e.g. Controls, Application Model, Graphics, etc.);
- fundamentals expert, with deep knowledge of software fundamentals such as security, performance & scalability, globalization/localization, accessibility, etc;
- passionate about code quality, passionate and capable code and design reviewer;
- striving on living on the absolute leading edge (and sometimes bleeding edge :) ) of the WPF technology;
- a capable problem solver and having great sensitivity and zeal for discovering and fixing quality issues in the platform;
- an effective team player.
We are currently looking for both junior and senior SDETs. You don't have to be all of the above in order to apply. You just have to be passionate, smart and willing to learn.
Software Architect
(see official job posting)
We are also looking for several software architects. Software architects are senior individual contributors with broad technical knowledge and experience, who are interested in having broad influence rather than being deep area experts.
A successful software architect on the team is:
- an experienced software engineer with broad knowledge and appreciation of advanced software design and development techniques;
- a passionate "code librarian", driving high code quality, as well as proper architectural layering, componentization and reuse across the organization;
- a fundamentals champion and driver;
- a technical leader and mentor;
- an effective design and code reviewer;
- very friendly and approachable. Willing to be randomized by folks asking for technical guidance and advice.
The Software Architects work closely with the managers and with other senior individual contributors on the team to form a coherent technical vision and strategy, matched with a pragmatic execution plan.
If you think you have what it takes to be successful in one of the best teams at Microsoft and you feel you are ready for a change, drop me a line. We offer working on the most advanced UI platform shipped by Microsoft to date, working alongside some of best and brightest engineering brains in the industry, a supportive and friendly team and practically limitless career growth opportunities.
A PC that holds all of your media (music, photos, home videos, movies), allows you to pause, record and play back live TV and looks like a regular consumer electronics device? Sure! It's called a Media Center PC (or Home Theater PC, or HTPC) and I felt it was a high time to assemble one.
The last time I assembled a PC was about 15 years ago as an undergrad student and, boy, those were simpler, purer times. It quickly became apparent that I would spend weeks figuring out what components to use in the PC, given the myriad of motherboards, CPU sockets, etc, etc, etc, so I looked for help on the web, and I came across this great article by Loyd Case.
So I just went ahead and duplicated the cheapest PC configuration recommended by Loyd. Here's what I ended up with:
| Component | Model | Notes | Price |
| Motherboard | Gigabyte GA-MA69GM-S2H | | $86 |
| CPU | AMD Athlon 64 X2 | | $116 |
| CPU Cooler | Scythe Ninja Mini | To replace the original cooler that came with the CPU | $31 |
| Graphics | ATI Radeon X1250 Internal with HDMI | Integrated on the motherboard | n/a |
| Audio | Integrated HD audio | Integrated on the motherboard | n/a |
| Memory | 2GB Kingston ValueRAM (KVR800D2N5K22G) | | $56 |
| Hard Drive | Western Digital WD7500AYYS 750GB | | $201 |
| Optical Drive | Lite-On LH-20A1 DVD Burner | | $36 |
| Case & PSU | Antec Fusion Black 430 | | $150 |
| TV Tuner | ATI TV Wonder HD 650 PCI-express | The package includes a MC remote control. Note: There are two problems with this tuner: a. I couldn't actually get this tuner to receive any over-the-air TV programming, although I tried several different antennas. I have as a result ordered a Hauppauge tuner. b. The remote that comes with the tuner is a RC5 remote, so it does not work with the integrated RC6 infrared receiver in the Antec box. So I ended up getting another remote (a RC6 one) from a friend, which worked beautifully. See below for pointers to a RC6 remote. | $130 |
| Total | | | $805 |
Putting together the PC took an evening. I installed Windows Vista Ultimate (a smooth uneventful installation, as long as you have a USB keyboard and a USB mouse handy), connected the PC to the Internet, to my TV signal source and to my TV and fired up Windows Media Center. The configuration I ended up with is:
The integrated graphics card on the motherboard conveniently provides HDMI output, so that's what I used to connect the TV to the Media Center PC. You will notice that I have not connected an audio system. I am just using the speakers of my TV (via the same HDMI cable), which frankly are good enough for us.
It took me about 2 days to rip all of my CDs (I used Windows Media Player to do that) and transfer all of my videos and pictures to the PC.
MCE Works Beautifully!
The Windows Media Center included with Windows Vista is an excellent piece of software and works perfectly for me with the above PC config (see the few gotchas I had to deal with). It has it all -- beautiful UI, an excellent set of discoverable features, a natural navigation model. It's just a great example of consumer software. We as a company should advertise it better...
Here are a few screen-shots:
TV Channel Guide
The TV channel guide is updated through Internet. This snapshot shows the channel guide superimposed on top of the currently displayed channel (NBC)
Recorded TV
Shows you representative frames from TV shows you have recorded. Notice that the currently played content is shown in a small PIP pane at the bottom left corner.
Picture Library
Browsing a large number of digital pictures is very easy. We have about 3000 pictures in our library and I have not noticed any degradation in performance or performance issues, when browsing through them. Importing your new pictures is always very easy - you just connect your camera via a USB cable and you get prompted to import the pictures.
Music Library
You can sort by various criteria (album, artists, etc) and you get optimized lists that help you quickly find what you are looking for. Notice how the CD art gets automatically loaded for any recognized album. This feature works very well even for fairly old and/or apocryphal CDs.
A Few Gotchas
Overall, setting up a media center PC has been a breeze. The problems that I hit were:
- Set-up:
- HDMI audio kept getting disabled. To fix this, open up Control Panel > Sound, open up the "Realtek HDMI Output" playback device, disable the device, log off, log on and re-enable the device:

- The integrated IR receiver in the Antec case did not work with remote that came with the TV tuner card. Apparently, the IR receiver is set up to recognize RC6 codes, and my remote was issuing RC5 codes, so I had to use the USB IR receiver that came with the remote (that works just fine -- you just have to be comfortable with the external receiver). Alternatively, get a MS MCE remote (e.g. this one). I approached the Antec support team with questions around this -- they were very responsive.
- The volume knob on the Antec case did not work initially. To fix the problem, I had to download and install the latest version of the iMon utility (from here) and uninstall the VFD utility which came on the CD with the Antec case, and which I had previously installed. iMon is just a souped-up version of VFD.
- The channel guide browsing performance tended to degrade noticeably if I had tuned to a channel before I hit the guide. To fix this, I had to switch to the "High performance" power plan (in Control Panel > Power Options)
- HD channels:
- You cannot get HD channels through you cable provider (see [5] below), so I recommend giving up cable TV (yeah, you'll have to fight your Nip/Tuck addition) and switching to a combination of over-the-Internet NetFlix and a TV antenna.
MCE Hardware Accessories and Software Add-Ins
You may consider getting a few hardware accessories:
| Accessory | Model | Notes | Price |
| Wireless keyboard /mouse | Microsoft Wireless Entertainment Desktop 7000 | A very slick, but somewhat expensive piece. Cheaper alternatives are the ZV1-00004 IR keyboard or the ZV7-00009 IR keyboard, both for $40. | $120 |
| Antenna | TBD | Over-the-air TV broadcasts are free and (in the US) of higher quality than what you can get through a cable TV provider (you can't get HDTV cable content even though you have an HDTV tuner - see [2] below). I have personally disconnected my cable and switched to an antenna (see [5] below). | TBD |
| MCE Remote | Microsoft A9O-00007 WinXP Media Center Infrared Remote Control | As discussed above, if you want to use the IR receiver integrated in the Antec case, you'd need to have a RC6 remote. | $39 |
I also recommend installing the following software (in suggested priority order):
| Software | Notes | Price |
| My NetFlix | MC add-in, which allows you to manage your NetFlix queue and watch streamed NetFlix movies (for as little as $8.99/month - Patrick Danino, one of our test architects, pointed me to this great deal) from within Media Center. Works great! | Free |
| FFDShow Codecs | You may need these codecs to be able to watch video files. | Free |
| ShowGallery hack | You can rip your DVDs to your drive and have MCE display them in a nifty DVD library. Check out this article by Max Zuckerman for a walk-through of how to do it. | Free |
| DVR MS Toolbox | Allows you (among other things) to automatically remove commercials from recorded TV. By the way http://TheGreenButton.com provides a wealth of MCE information (big thanks to Gilman Wong - our dev manager, who is also a big MCE aficionado - for pointing me to it) | Free |
Pearls of MCE Wisdom
Here are a few articles that I'd recommend to any Media Center enthusiast:
[1] Build a Windows Vista Home Theater PC is the excellent article by Loyd Case I used to build our media center PC.
[2] Planning Your Media Center PC: Choosing Your TV Source provides the best description of the different sources of TV signal I have come across.
[3] Review: Antec Fusion Black 430 provides a good review of the Antec PC case.
[4] This post explains how to play CD+G karaoke files in MCE (ok, I admit, I have a few of those lying around...)
[5] All About HDTV Antennas walks you through choosing an HDTV antenna. AntennaWeb.org shows the available over-the-air channels in your ZIP code.
Introduction
This article describes hosting of a Win32 user control in a WPF window. It is supplemented by the following two projects, which show working examples of the material presented in the document:
- Win32ControlInWpfWindow_CompositeWin32Messages
- Win32ControlInWpfWindow_SimpleWin32Messages
The only difference between the two projects is the Win32ListBoxHost.cs file. The differences between the two versions of the file are related to the material covered in the “Simple” Messages vs “Composite” Messages section below. You can view the differences between the two versions of the file by using a utility such as WinDiff.exe, which is shipped with the Windows SDK.
This article is based on the material available on the WPF/Win32 interoperability portal on MSDN.
Hosting of a Win32 Control in a WPF Window
In traditional Win32 programming, user controls (buttons, listboxes, etc.) are instantiated through a call to the CreateWindow or CreateWindowEx APIs. Every control has a unique (per session) identifier of type HWND and is recognized as a separate window (albeit a child window) by the window manager of the OS. What this means is that the window manager of the OS has the ability to do hit-testing of the user control without the assistance of the parent window and is thus capable of sending window messages (e.g. WM_LBUTTONDOWN, etc.) directly to the user control. These window messages are typically intercepted and processed by the message loop of the parent window, but can also be processed by the user control.
In WPF programming user controls are not separate windows with separate HWNDs. Hit-testing is accomplished by the Visual layer in the WPF stack. Thus the window manager of the OS sends messages only to the top-level WPF window.
Hosting of a Win32 user control in a WPF window is accomplished using the following steps:
- Create a class deriving from HwndHost;
- In the HwndHost-derived class implement 3 methods declared in HwndHost (BuildWindowCore, DestroyWindowCore and WndProc):
class MyHost : HwndHost
{
// Public adapter interface goes here
protected override HandleRef BuildWindowCore(HandleRef hwndParent)
{
// PInvoke to CreateWindow(Ex)...
return new HandleRef(this, hwnd);
}
protected override void DestroyWindowCore(HandleRef hwnd)
{
// PInvoke to DestroyWindow
}
protected override IntPtr WndProc(
IntPtr hwnd,
int msg,
IntPrt wparam,
IntPtr lparam,
ref bool handled)
{
// Handle incoming messages here.
// The incoming messages are typically delegated
// to the hosted control.
}
}
You use the BuildWindowCore to instantiate the Win32 user control you want to host. This is typically done through a call to the CreateWindow / CreateWindowEx API. Similarly, in DestroyWindowCore you destroy your Win32 user control, typically by a call to the DestroyWindow API.
The WndProc method allows you to handle incoming window messages.
- In your HwndHost-derived class (MyHost in this particular example), declare an adapter interface to allow communication with the hosted Win32 control. In order to ensure reusability of the host class in different WPF applications, you should strive to avoid any Win32 idiosyncrasies in the interface. Instead, the adapter interface should conform to the .NET coding and style guidelines and should hide the fact that there is an underlying Win32 control.
For example, if your HwndHost-derived class is wrapping a Win32 listbox, then it probably makes sense to expose basic listbox methods such as:
· AddItem
· DeleteItem
· SelectedItemIndex {get; set}
· SelectedItemText {get;}
· SelectionChanged event (see the “Communicating Win32 Events to the WPF Window” section later in this document)
Conversely, it is not a good idea to expose a method such as SendMessage, wrapping the Win32 SendMessage API.
- In the XAML file declaring the UI of your WPF window, add a declaration for your HwndHost class:
<Window
x:Class="Win32ControlInWpfWindow.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:custom="clr-namespace:Win32ControlInWpfWindow;assembly="
Title="Win32 Control in a WPF Window"
Height="500" Width="600"
>
<StackPanel>
<Button Click="ButtonAddItemOnClick">Add Item</Button>
<custom:Win32ListBoxHost x:Name="listbox" Width="100" Height="100"/>
</StackPanel>
</Window>
Note how the XAML file above defines the name space for your HwndHost-derived class (the “custom” namespace) and the assembly where the class is implemented. In this particular case the “assembly=” directive points to nothing, which indicates that the host class is implemented in the same assembly as the one of the MainWindow class.
“Simple” Messages vs “Composite” Messages
In a traditional Win32 application, you display a number of Win32 user controls in a top-level Win32 window. The top-level window is typically handling all window messages resulting from interaction of the user with the controls through a top-level WindowProc.
As the user interacts with the controls on the window, the top-level WindowProc receives both “simple” messages (e.g. WM_LBUTTONDOWN, etc.) that are generated by the OS window manager as well as “composite” messages (e.g. WM_COMMAND, etc.) that are generated by the user controls and sent as notifications to the parent window.
These “composite” notifications present a problem in the WPF hosting case, because there is no parent window WindowProc to process them. As a result, in the code below would not really work as expected:
class MyHost : HwndHost
{
protected override HandleRef BuildWindowCore(HandleRef hwndParent)
{
_hwndListBox = CreateWindowEx(
0, "listbox", "",
WS_CHILD | WS_VISIBLE | LBS_NOTIFY | WS_VSCROLL | WS_BORDER,
0, 0,
(int)Width, (int)Height,
hwndParent.Handle,
IntPtr.Zero,
IntPtr.Zero,
0);
return new HandleRef(this, _hwndListBox);
}
protected override IntPtr WndProc(
IntPtr hwnd,
int msg,
IntPrt wparam,
IntPtr lparam,
ref bool handled)
{
switch (msg)
{
case WM_COMMAND:
// This code-path will never get hit as the listbox control will
// never receive the WM_COMMAND message that it posts to its parent
break;
case WM_LBUTTONDOWN:
// This code-path will get hit as the listbox control will
// be receiving the message from the OS window manager
break;
}
}
...
}
In most cases handling “simple” messages in the WndProc method is sufficient, although it may be somewhat cumbersome.
There are, however, cases in which you would want to receive “composite” messages. To achieve this, you need to create an artificial parent HWND, so that you can receive the “composite” notifications, generated by the hosted child windows. In other words you end up with the following general structure:
![clip_image002[6]](http://blogs.msdn.com/blogfiles/ivo_manolov/WindowsLiveWriter/WPFWin32InteropPart2HostingWin32Controls_12F45/clip_image002%5B6%5D_thumb.jpg)
This is achieved as follows:
class MyHost : HwndHost
{
protected override HandleRef BuildWindowCore(HandleRef hwndParent)
{
_hwndListBoxParent = CreateWindowEx(
0, "static", "",
WS_CHILD,
0, 0,
(int)Width, (int)Height,
hwndParent.Handle,
IntPtr.Zero,
IntPtr.Zero,
0);
_hwndListBox = CreateWindowEx(
0, "listbox", "",
WS_CHILD | WS_VISIBLE | LBS_NOTIFY | WS_VSCROLL | WS_BORDER,
0, 0,
(int)Width, (int)Height,
_hwndListBoxParent,
IntPtr.Zero,
IntPtr.Zero,
0);
return new HandleRef(this, _hwndListBoxParent);
}
...
Private IntPtr _hwndListBoxParent = null;
Private IntPtr _hwndListBox = null;
}
Communicating Win32 Events to the WPF Window
With the code above we can capture and process the window messages sent to the hosted Win32 user control. We do that in the WndProc method.
In addition to that we need to be able to inform interested WPF elements of the fact that we have received a certain event. For example, a hosted Win32 button may need to inform a WPF textbox that is has been clicked, a hosted Win32 listbox may need to inform a WPF textbox that the selection in the listbox has been changed, etc. The traditional way to do expose that capability in .NET is through events.
So we declare a public event and a protected event handler as follows:
class MyHost : HwndHost
{
...
public event EventHandler SelectionChanged;
protected void OnSelectionChanged(EventArgs args)
{
EventHandler handler = SelectionChanged;
if (handler != null)
{
handler(this, args);
}
}
...
}
This allows the users of the class to write code such as:
class Test
{
public static void Main()
{
...
myHost.SelectionChanged += MySelectionChangedHandler;
...
}
public void MySelectionChangedHandler(EventArgs args)
{
// This method gets called whenever someone changes the selection in the Win32
// control (which is presumably a listbox) hosted in MyHost.
}
...
}
Adding Tab and Accelerators Support for the Hosted Win32 Control
One current problem that you will see in the application is that keyboard navigation does not work well with the Win32 control. Keyboard navigation has several aspects:
a) Enabling tabbing into and out of the hosted Win32 control (listbox)
b) Enabling keyboard navigation within the hosted Win32 control (e.g. moving the selection in the listbox)
c) Supporting access keys
In order to achieve a) and b), your HwndHost-derived class needs to implement two methods of the IKeyboardInputSink interface: TabInto and TranslateAccelerator.
The TabInto method gives you (as the name suggests) tabbing into the Win32 listbox (by pressing either Tab or Shift+Tab). In this particular case, the implementation of TabInto is trivial because we only have a single Win32 control:
class Win32ListBoxHost : HwndHost, IKeyboardInputSink
{
...
bool IKeyboardInputSink.TabInto(TraversalRequest request)
{
if (request.FocusNavigationDirection == FocusNavigationDirection.Next)
{
NativeMethods.SetFocus(_hwndListBox);
}
else
{
NativeMethods.SetFocus(_hwndListBox);
}
return true;
}
...
}
The TranslateAccelerator method gets called whenever the OS sends keyboard messages (WM_KEYDOWN or WM_SYSKEYDOWN) to the application. We use the method to intercept pressing of the up and down arrow so that we can change the selected item in the hosted Win32 listbox:
class Win32ListBoxHost : HwndHost, IKeyboardInputSink
{
...
bool IKeyboardInputSink.TranslateAccelerator(ref MSG msg, ModifierKeys modifiers)
{
bool isHandled = false;
if (msg.message == NativeMethods.WM_KEYDOWN)
{
if (msg.wParam == (IntPtr)NativeMethods.VK_UP)
{
if (this.SelectedItemIndex > 0) { this.SelectedItemIndex--; }
else { this.SelectedItemIndex = 0; }
isHandled = true;
}
if (msg.wParam == (IntPtr)NativeMethods.VK_DOWN)
{
this.SelectedItemIndex++;
isHandled = true;
}
}
return isHandled;
}
}
The only thing that remains is supporting access keys (also known as mnemonics). In order to do that, you need to provide an implementation for the IKeyboardInputSink.OnMnemonic method.
Conclusion
The attached projects demonstrate the final solution for hosting a Win32 listbox in a WPF window. The final interface of the HwndHost-derived Win32 listbox container class is:
class Win32ListBoxHost : HwndHost, IKeyboardInputSink
{
public void AddItem(string item);
public void DeleteItem(int itemIndex);
public int SelectedItemIndex { get; set; }
public string SelectedItemText { get; }
public event EventHandler SelectionChanged;
protected override HandlerRef BuildWindowCore(HandleRef hwndParent);
protected override void DestroyWindowCore(HandleRef hwnd);
protected virtual void OnSelectionChanged(EventArgs args);
protected override IntPtr WndProc(IntPtr hwnd, int message,
IntPtr wParam, IntPtr lParam, ref bool handled);
bool IKeyboardInputSink.TabInto(TraversalRequest request);
bool IKeyboardInputSink.TranslateAccelerator(ref MSG msg, ModifierKeys modifiers);
}
For demonstration purposes only, I have included both a project that only uses “simple” (aka “raw”) window messages only and one that uses composite window messages. The only differences between the two projects are in the Win32ListBoxHost.cs file. In most real-world situations, you will end up using “composite” window messages – otherwise you would have to re-implement parts of the business logic of the component you are hosting, which is obviously undesirable.