Category Archives: Media Center

When Resharper isn’t so sharp

One of the things I wanted to add to MceFM was to let users tell Last.fm to Love/Ban songs.

I was using the RegisterRawInputDevices Windows call to listen for events generated by the remote control.  This takes a RAWINPUTDEVICE structure as a parameter:

    [StructLayout(LayoutKind.Sequential)]
    internal struct RAWINPUTHEADER {
      [MarshalAs(UnmanagedType.U4)] public int dwType;
      [MarshalAs(UnmanagedType.U4)] public int dwSize;
      public IntPtr hDevice;
      [MarshalAs(UnmanagedType.U4)] public int wParam;
    }

My code was working fine, and then suddenly stopped working.  I lost at least an hour tracking back what I’d changed recently, and then finally realized that I’d run Resharper’s Reformat Code tool:

image

Notice that last item?  This is what it did to the structure:

    [StructLayout(LayoutKind.Sequential)]
    internal struct RAWINPUTHEADER {
      [MarshalAs(UnmanagedType.U4)] public int dwSize;
      [MarshalAs(UnmanagedType.U4)] public int dwType;
      public IntPtr hDevice;
      [MarshalAs(UnmanagedType.U4)] public int wParam;
    }

The RegisterRawInputDevices call was falling over because the structure was totally out of whack.  I’m still a big fan of Resharper — and this is marked as fixed in the next release.

Creating MSAS sinks in C# without using MediaState

Microsoft’s Window Media Center has a mechanism to notify you of events inside Media Center, called the Media State Aggregation Service (MSAS).

The Media Center SDK includes a .NET assembly called MediaState, which you can use to hook up C# to MSAS, however it is possible to build C# classes that hook directly to MSAS without using the MediaState assembly.

To do so, create a C# Class Library project, and add a COM reference (Project|AddReference|Browse) to c:\windows\ehome\ehmsas.exe.

Next create a couple of classes, one called Sink and the other called Session.

Make the Sink class implement the MediaStatusSink interface from ehMSASLib imported COM library:

using ehMSASLib;
using System.Diagnostics;
using System.Runtime.InteropServices;

namespace TestMSAS {
  [ComVisible(true)]
  [GuidAttribute("360d8298-97d9-4058-9052-b91efe76d3ae")]
  public class Sink : MediaStatusSink {
    public Sink() {
      string logFile = string.Format("{0}MsasSink.log",
        System.IO.Path.GetTempPath());
      Trace.Listeners.Add(new TextWriterTraceListener(logFile));
      Trace.AutoFlush = true;
      Trace.TraceInformation("Sink started");
    }

    public void Initialize() {
      Trace.TraceInformation(("Sink.Initialize called"));
    }

    public MediaStatusSession CreateSession() {
      Trace.TraceInformation(("Sink.CreateSession called"));
      return new Session();
    }
  }
}

I’ve made the CreateSession method return a new instance of the Session class, and also made the Sink class public and added the ComVisible(true) attribute to make it visible from COM. You should generate and use your own Guid using Tools|Create GUID.

Make the Session class implement the MediaStatusSession interface:

using System;
using System.Diagnostics;
using System.IO;
using System.Net;
using ehMSASLib;

namespace TestMSAS {
  class Session : MediaStatusSession {
    void IMediaStatusSession.MediaStatusChange(Array tags,
                                               Array properties) {
      Trace.TraceInformation("Session.MediaStatusChange called");

      for (int i = 0; i < tags.Length; i++ ) {
        MEDIASTATUSPROPERTYTAG tag =
          (MEDIASTATUSPROPERTYTAG) tags.GetValue(i);
        object value = properties.GetValue(i);
        Trace.TraceInformation("Tag {0}={1}",
                               tag,
                               value);
      }
    }

    public void Close() {
      Trace.TraceInformation(("Session.Close called"));
    }
  }
}

We are going to put the C# assembly in the GAC, so make sure it is strongly named (Project|Properties|Signing|Sign the assembly):

image

Once you have built your project, register the resulting DLL for COM access using the regasm command, and install both the DLL, and the Interop.ehMSASLib.dll interop assembly in the GAC using the gacutil command (I missed registering the interop assembly and spent a couple of hours banging my head against the wall):

image

Finally, fire up the registry editor, find the HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{…} key for your Sink class (I searched for it to find it), and add a new KEY under the “Implemented Categories” key, with the name “{FCB0C2A3-9747-4C95-9D02-820AFEDEF13F}” (no quotes).  This tells MSAS that your component acts as an MSAS Sink:

image

To test, I generally kill the ehmsas process from the task manager, and the fire up Media Center, which restarts the ehmas process.

You can also debug directly by setting the debug executable to be c:\windows\ehome\ehmsas.exe and setting the executable paramerers to “-embedded”

Bulk fetching images for dvr-ms files

When using Windows Media Center, there is a hidden option to make it display a “my dvds” menu item.  As well as DVDs, it also shows all your recorded films.

By default there is no thumbnail image displayed for these recorded films (which end in the “dvr-ms” extension):

image

You can make a thumbnail be displayed  by downloading the appropriate cover art jpeg image, and name it the same as the film’s file, but with the “.jpg” extension, instead of “.dvr-ms”.

I have well over a hundred such films, and it was going to take all night to download each film’s cover from amazon/google, so I’ve created a program which does it in bulk.  You chose a directory containing your dvr-ms files, and for each film that doesn’t already have an image, it looks up the film name in Google Images, and lets you choose the appropriate image:

image 

After you click on the image you want, it creates the JPEG file for the film, and carries on to the next film.  It uses the metadata in the DVR-MS files to determine if the file is a film, and only prompts you for films.

image

You can download the program here.  Download it to your computer before running it.  It is written in C#  and is free for you to use — use it entirely at your own risk– feel free to report bugs here though.

Referencing external assemblies using MCML

MCML is Windows Media Center Markup Language.  You use it to define the GUI for your Windows Media Center applications.

I’ve been banging my head against the wall trying to get a reference to a .NET assembly to work in MCML.  The example in the documentation uses the syntax:

xmlns:cor="assembly://MSCorLib/System"

Where MSCorLib is the name of the assembly in the Global Assembly Cache.

This worked fine for me where the assembly contained the current Media Center Application:

xmlns:ext=assembly://MceAppAssembly/SomeNamespace

However when I wanted to reference a different external assembly (that was also in the GAC) I was getting an error loading the MCML page, indicating that the assembly could not be loaded.

In the end I found out that I needed to use a strong assembly name:

xmlns:ext="assembly://ExternalAssembly, Version=1.0.0.0, Culture=neutral,
  PublicKeyToken=0123456789abcdef/SomeNamespace"

I guess this is pretty obvious, but I’m also guessing that I won’t be the only one to waste an hour or so on this.  The documentation doesn’t give an example like this (just the weak named reference), although it does give strong named examples for resource references.