Monthly Archives: July 2008

BeebMC 2.0 released: Listen Again supported

I’ve just released a new version of BeebMC, adding support for "Listen Again":




If/when the BBC update their web site or RSS feeds then BeebMC will probably break — leave a comment and I’ll do what I can to fix it.  Many thanks to the BBC for making all this content available.

BeebMC is available here:

The Channels.xml file under C:\ProgramData\Atadore\BeebMC has been extended to include the URL for each channel’s RSS feed.  Feel free to edit it to add/remove/modify channels:

  <Description>BBC 1Xtra</Description>

I’m going to try to add extender support next.  Subscribe to the "BeebMC" category in my blog to be notified of updates:

Screencast: Creating a simple Media Center Application

I’ve had some demand for the source for my simple application that plays BBC Radio inside Media Center.

I thought it might be more valuable if I put together a screencast introducing how I created the application from scratch, although the source is below too.

I assume your are familiar with .NET and C#, and have perhaps browsed through the Media Center documentation a little.  If you are an experienced Media Center developer then move along, move along, there is nothing here to see.

The first screencast walks through the simple application that gets created for you when you create a new Media Center Application.  I show how it works, and how you can build, install, and run it.  It is available to be streamed or downloaded here:

The second screencast starts when the first one leaves off, and shows how I modified the initially created application to play BBC Radio.  It is here:

The final project is here.  It isn’t quite the same as the BeebMC application (it doesn’t load the channels from an XML file, and has no error checking), but feel free to play around with it.

I recorded them in one go quite late on a Saturday night, and I stumbled a couple of times with the terminology – please forgive the occasional mistake.

Hope this is useful! Do let me know.

BeebMC – BBC Radio addin for Windows Media Center

I’ve developed a small  BBC Radio Media Center addin mainly for my own use, which I’m making available here for free for anyone else that wants it.

[I’ve since posted a new version of BeebMC here . It supports “Listen Again”.   I recommend going to this posting to read about it and download it.]

There are a couple of restrictions:

  • Your need Real Player installed
  • You need version 3.5 of the .NET framework installed.  It is available here if you don’t have it (or if you are not sure).
  • It will not work with Extenders, since the BBC streams using Real Audio.

I can’t promise a lot of support, but reply here if you have problems using it and I’ll help if I can.

Once installed you’ll find it under the Music menu:


Click on a channel to play that channel:


You can customize it by editing the Channels.xml file you will find under C:\ProgramData\Atadore\BeebMC. Add channels by adding a Channel element with the appropriate description, picture and URL for playing the channel.


[I’ve since posted a new version of BeebMC here . It supports “Listen Again”.   I recommend going to this posting to read about it and download it.]

.NET Code Injection

In this post I’ll show how you can inject your own .NET code into a process that is already running the .NET framework.

I needed to do this when developing for Windows Media Center because there is no official documented way to determine what page is currently being displayed in Media Center.

I wanted to know when the user is showing the Media Center “now playing” page.

Media Center addins run in a completely separate process to the main Media Center process, which is ehshell.exe.  Calls you make in your addin are remoted across to the Media Center ehshell.exe process.

The solution works using:

  • an “Injecter” C# class  which uses CreateRemoteThread to load a Bootstrap DLL into the ehshell.exe process
  • The “Bootstrap” C++ DLL which is injected into the ehshell.exe process uses the CLR Hosting API to attach to the default .NET domain, and then load an instance of the “Injectee” C# class
  • The “Injectee” C# class is loaded by the “Bootstrap” DLL and runs within the ehshell.exe process.  It uses reflection to subscribe to an event within the ehshell.exe process and then sends an interprocess message when the event fires

The “Injecter”

Using Reflector, I looked around at the ehshell.exe assembly, and related assemblies, and eventually discovered that there is a PageChanged event fired by the ServiceBus.UIFramework.PageBasedUCPService class:


What is more, there is a static PageBasedUCPService.DefaultUCP method to return a PageBasedUCPService instance.

There are of course a couple of problems.  The first problem being that these classes are internal to the ehshell assembly,  the second issue being that these are all running in a totally separate process to my addin.

I searched a little, and came across this example showing how you could use the CreateRemoteThread from .NET to inject your own native code into a remote process.

Essentially it opens a handle to the remote process, finds the LoadLibrary system call’s address in the remote process, allocates a chunk of memory in the process, and fills the memory with a LoadLibrary call to load a DLL that you specify, and then creates the thread in the remote process, passing the address of the chunk of memory as the starting point for the thread.

I recommend taking a look at the CRT call in the example.  I’ll not be duplicating the code here.

To use the CRT call, I first find Media Center:

public static Process FindMediaCenterProcess() {
  // Could be more than one if an extender is running too
  foreach (Process process in Process.GetProcessesByName("ehshell")) {
    if (process.SessionId == Process.GetCurrentProcess().SessionId) {
      return process;
  return null;

I can then call the CRT method:

Process mediaCenterProcess = FindMediaCenterProcess();
IntPtr hwnd;
string error;
CRT(mediaCenterProcess, dllPath, out error, out hwnd);

The dllPath is the full path to my C++ DLL, in my case this was

Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles) +

The “Boostrap DLL”

The InjectBootstrap.dll is a pretty simple C++ library project.  The DllMain calls a bootstrap function when the process is loaded:

                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
    switch (ul_reason_for_call)
    return TRUE;
My bootstrap function attaches to the default .NET domain and loads an instance of one of my own classes:
#include "stdafx.h"
#include <stdio.h>
#include "objbase.h"
#include "MSCorEE.h"
#import "C:\Windows\Microsoft.NET\Framework\v2.0.50727\mscorlib.tlb" raw_interfaces_only
using namespace mscorlib;

void Bootstrap() {
    OutputDebugString(L"MceFM Bootstrap Started");

    CoInitializeEx(0, COINIT_MULTITHREADED );
    ICorRuntimeHost* pICorRuntimeHost = 0;
    HRESULT st = CoCreateInstance(CLSID_CorRuntimeHost, 0, CLSCTX_ALL,
        IID_ICorRuntimeHost, (void**)&pICorRuntimeHost);
    if(!pICorRuntimeHost) return; // Clean up and log errror ...


    if(!hEnum) return; // Clean up and log errror ...

    IUnknown* pUunk = 0;
    st = pICorRuntimeHost->NextDomain(hEnum, &pUunk);
    if(!pUunk) return; // Clean up and log errror ...

    _AppDomain * pCurDomain = NULL;
    st = pUunk->QueryInterface(__uuidof(_AppDomain), (VOID**)&pCurDomain);
    if(!pCurDomain) return; // Clean up and log errror ...

    _bstr_t assemblyName =
        "Last, Version=, Culture=neutral, PublicKeyToken=792d614cdf38e9ce";
    _bstr_t typeName = "MceFM.Last.Inject.Injectee";

    _ObjectHandle* pObjectHandle = 0;

    pCurDomain->CreateInstance(assemblyName, typeName, &pObjectHandle);


The “Injectee”

Finally we come to the Injectee class, which is loaded by the DLL, and runs inside the remote (ehshell.exe) process.  It is in a strongly named assembly which is stored in the GAC, so that the bootstrap call above can find it (note the strong name in the assembly name bstr).

I use a static constructor (which runs as soon as the class is loaded).  In this static constructor I subscribe to the event:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net;
using System.Reflection;
using System.Reflection.Emit;
using System.Threading;

namespace MceFM.Last.Inject {
  public class Injectee {

    static Injectee() {
      try {
        Assembly ehshell = Assembly.Load("ehshell");

        // Get the PageBasedUCPService type
        Type pageBasedUCPServiceType =

        // Call static DefaultUCP method to get a PageBasedUCPService instance
        const BindingFlags bindingFlags = BindingFlags.DeclaredOnly |
          BindingFlags.Static | BindingFlags.Public | BindingFlags.GetProperty;
        object[] args = new object[0];
        object defaultUCP = pageBasedUCPServiceType.InvokeMember("DefaultUCP",
          bindingFlags, null, null, args);

        // Get a reference to the PageChanged event
        EventInfo pageChangedEventInfo =
        Type pageChangedDelegate = pageChangedEventInfo.EventHandlerType;

        // Get the MethodInfo for the method to be called when the event fires
        MethodInfo newPageHandlerMethodInfo =

        // Build an array of types used for new method we shall dynamically emit
        Type pageType = ehshell.GetType("ServiceBus.UIFramework.Page");
        Type[] pageChangedDelegateParameters = new[] { pageType };

        // Need a dynamic method because we can't create a method that has
        // the Page type as a parameter
        DynamicMethod dynamicHandler = new DynamicMethod("", null,
          pageChangedDelegateParameters, typeof(Injectee));
        ILGenerator ilgen = dynamicHandler.GetILGenerator();
        ilgen.Emit(OpCodes.Call, newPageHandlerMethodInfo);

        if(pageChangedDelegate != null) {
          // Subscribe to the event
          Delegate dEmitted = dynamicHandler.CreateDelegate(pageChangedDelegate);
                                                     new object[] {dEmitted});
      } catch(Exception ex) {
        Trace.TraceError("Unexpected error in Injectee initializer: {0}", ex);

    // Queue of new pages that have been navigated to.  Decouples event handler
    // from re-despatching of the event to the addin process that is told
    // of the new event.
    private static readonly Queue<string> newPages = new Queue<string>();

    // Indicates whether background thread that despatches events is running
    private static bool notifierActive;

    // Called when Media Center navigates to a new page
    public static void NewPageHandler(object page) {
      Trace.TraceInformation("New Page: " + page);
      lock(newPages) {
        if(!notifierActive) {
          Thread thread = new Thread(NewPageNotifier) {IsBackground = true};
          notifierActive = true;

    // Thread that despatches events to addin process telling it that
    // a new page has been navigated to
    private static void NewPageNotifier() {
      while(true) {
        string page;

        lock(newPages) {
          while(newPages.Count == 0) {
          page = newPages.Dequeue();

        try {
          // Use whatever interprocess notification mechanism you wish.
          // WCF could be good.  Here I use a simple web call.  My
          // addin has a web server in it to receive these calls.
          WebClient webClient = new WebClient();
          webClient.QueryString[Server.PAGE_QUERY_STRING] = page;
                                   + Server.MCE_PAGE_CHANGED_ACTION);
        } catch (Exception ex) {
          Trace.TraceError("Error while sending new page notification: {0}", ex);
#pragma warning disable FunctionNeverReturns
#pragma warning restore FunctionNeverReturns

The Result

In my web server running within my addin (which is notified by the “NewPageNotifier” method above), I keep track of which is the current page, and log information when the page changes:

Server notified of page change MediaCenter.Audio.AudioNowPlayingPage
Server notified of page change MediaCenter.Audio.AudioNowPlayingTracklistPage

All this means that if you are a user and want to tell that you love a track that is currently playing then you can press the right-button on your remote control on the “now playing” page using my MceFM addin.

I use low level system hooks to know when you press the right button, and the above technique to know that you are on the “now playing” page:


Word if warning.  If/When Media Center changes its internal structure this technique will completely fall over.  Use sparingly, entirely at your own risk,  to do the seemingly impossible.