Using MediaState.dll with GAC'd Add-Ins

Update (10/14/2005): MediaState.dll in the new SDK released today is signed. You can download it at https://www.microsoft.com/downloads/details.aspx?FamilyId=1D836C29-ABD5-4FDD-90C5-5C5ABAE97DB4&displaylang=en .

The Media State Aggregation Service (MSAS) in Windows XP Media Center 2005 provides media event information about the current state of the Media Center. This includes information such as track or channel number changes and time elapsed. The MSAS service is implemented as a local COM server and distributes information about property changes it experiences to one or more registered media status sinks. Note, however, that sinks are only notified when a property changes, and that notification only includes the current state of the changed property, not the current state of all properties.  This means that if you write a sink that needs to know the current state of all properties in the system, it must listen for all events and track the current state of all properties.  And in order to write a managed add-in for Media Center that can query for the current state, you need to not only create such an MSAS add-in, but you also need to implement some mechanism for communicating between the managed add-in running in Media Center and the sink running in the MSAS service process.

To make this easier, the Windows XP Media Center 2005 SDK provides the MediaState library, which is composed of three DLLs. The MSASState.dll contains the MSASState.MediaStatusSink class, a managed implementation of the unmanaged IMediaStatusSink COM interface.  When registered with MSAS, the MediaStatusSink creates an MSASState.MediaStatusSession object (MediaStatusSession implements the unmanaged IMediaStatusSession COM interface), which listens for all MediaStatusChange events and writes information about each to a memory-mapped file.  To do this, it utilizes classes from MemMapFile.dll, also included with the SDK.  The third DLL included with the MediaState library, MediaState.dll, provides a managed object model for then accessing that memory-mapped file from an add-in running in Media Center.  In theory, this makes it easy for an add-in to access a plethora of information about the current state of the Media Center.  For example, if an add-in wants to determine the current live TV channel being watched, it can use code something like:

    MediaState state = new MediaState();
    int currentChannel = state.TV.Channel;

Unfortunately, there's a bit of an inconsistency in the SDK (at least in the current release) that makes this slightly more challenging.  Typically, one registers a managed add-in in the global assembly cache (GAC), as outlined at https://msdn.microsoft.com/library/en-us/medctrsdk/htm/registeringanaddinwithmediacenter.asp.  In order to use MediaState.dll from your add-in, typically you'll add a reference from your add-in assembly to MediaState.dll.  But in order to install your assembly into the GAC, it must have a strong-name, and in order to for a strong-named assembly to reference another assembly, that referenced assembly must also have a strong-name (and should be installed into the GAC).  The problem is that MediaState.dll doesn't have one. While there are a few workarounds to this, the most convenient is to give MediaState.dll a strong-name, and with Visual Studio .NET and/or the .NET Framework SDK installed, this takes only a couple of commands at the command prompt.

Open the Visual Studio .NET command prompt (if you don't have Visual Studio .NET installed, you can still do this, but the commands used will need to use the full paths to the utilities, or you'll need to manually augment your path environment variable; the VS.NET command prompt simply makes sure the env vars are configured appropriately).  Change to the Media State directory (with my installation, this is C:\Program Files\Microsoft\Microsoft Windows XP Media Center SDK\MSAS Sample\MediaState). 

First, we need to create a new strong-name key.  To do so, use the sn.exe tool:

    sn -k MediaState.snk

This creates a new key named MediaState.snk in the current directory.  With that in place, we need to disassemble MediaState.dll, and for that, we use the very handy ildasm.exe:

    ildasm /out:MediaState.il MediaState.dll

This diassembles MediaState.dll to a new Microsoft Intermediate Language (MSIL) file MediaState.il (it also saves the resources for the assembly to a file named MediaState.res).  Now, move the original MediaState.dll out of this directory to some place safe, as a backup just in case something goes wrong.  Finally, reassemble the DLL with the ilasm.exe tool:

    ilasm /key:MediaState.snk /out:MediaState.dll /dll MediaState.il

This tells ilasm.exe to reassembly MediaState.il (and the associated .res file) into a DLL named MediaState.dll, using the strong-name key MediaState.snk to sign the compiled assembly.  You'll now have a signed MediaState.dll which can be referenced by a strong-named add-in assembly and installed into the GAC.