Damian Mehers' Blog Android, VR and Wearables from Geneva, Switzerland.

20May/0817

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"

Comments (17) Trackbacks (0)
  1. Damian,

    Thanks for the post on creating the MSAS sink in C#. Following your steps makes it very easy. I do have one question. When it came time to do the strong name for my DLL I chose “create a new key file”, gave it a name and a password. When I searched for the CLSID of my installed DLL, I have exactly the same CLSID as your example (starts with 360D8298-). Shouldn’t the act of creating a new key file create a different CLSID?

    Obviously, if someone installed your DLL & my DLL we’d have a CLSID collision and presumably only the last one registered would be active. Or am I not understanding something about the PFX /signing process?

  2. Hi Mark,

    I think you might have missed the step “You should generate and use your own Guid using Tools|Create GUID”

    Hope this helps!

    /Damian

  3. Damian,

    Sorry, I see on a bit more study where the GUID came from for the sink – right in the code on the sink class. Presumably, one should generate a GUID and replace yours with the generated one. That makes total sense now.

    The GUID for the classid is totally unrelated to the naming keys. Of course, it makes sense now…

  4. Absolutely correct – Read directions? No just copied the code and went! Sorry…

  5. Hi Damian … great work … I’ve tried it out and it worked first time … brilliant. The project I am working on uses the Linksys extenders and amazingly I can see the Media State info for the 3 I have on the network. Only problem is that all the Media State info for all three extenders appear mixed up together. I have been racking my brain to extract the info separately.
    Any ideas you might have would be greatly appreaciated.

    Johno

  6. Damian … got the answer myself by including the System.Environment.UserName in the reporing.

    All the best
    Johno

  7. Thanks Johno – I was racking my brains but apart from running through the tags I couldn’t think of anything — I really appreciate you taking the time to post an update.

    /Damian

  8. Hi again Damian … did you ever manage to deploy your MSAS sink solution. I’ve got it working beautifully on my dev machine but when I deploy it I can only get events from the actual Media Center UI and not the extenders. Appreciate your perspective.

    Johno

  9. Hi Johno,

    I did hit this kind of problem, and ended up using a different mechanism to receive the events, using an embedded hidden media player, which reflects the events fired by the media player used by Media Center — take a look at this post:
    http://discuss.mediacentersandbox.com/forums/thread/6581.aspx

    I’m hoping to put MceFM on Codeplex in the next couple of days, and it would include the source for embedding Media Player (although I found the basic code elsewhere on the web).

    /Damian

  10. Thanks Damian … I had only just come accross your post at Media Center Sandbox as another potential solution to the problem. Unfortunately I am not a C++ guy … only VB and C#. It looks like the IWMPRemoteMediaServices Interface is only available for C++. I will be looking forward though to checking it out when you post.

    Thanks again Johno

  11. Hey Damian … not sure if you are still interested in this as I know you have another solution happening but I thought I’d let you know that I finally got it all working … Needed to add the following registry entry:

    HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Media Center\Service AlwaysUseFPD=1

    Got MSAS state for MCe, extenders plus on deployed project.

    thanks for all you help along the way …

  12. When attempting to add a reference to the ehmsas.exe I get and error saying that it couldn’t be added and to make sure it’s a valid assembly or COM component. I’m running Vista 64bit developing in Visual Studio 2008. Thoughts?

  13. Hi Chad,

    I’m not sure why that should happen … could you try opening it with Reflector or ILDASM and see if those work?

    /Damian

  14. Hi dmehers !

    I compile your dll and it’s ok but it’s impossible for me to use it…
    How can I use your dll for exemple to get the mediastate status change and put the result to a textbox using a timer or when I click on a button ?

    Thanks a lot for help!!

  15. Hi Damian,

    I too have found the WMPRemote code you are utilizing and while it appears to work great for remotely controlling Media Player, it does not appear to be responding to events fired from Windows 7 MCE. Is this something that has changed in Windows 7? I don’t have a vista box to test with anymore unfortunately.

  16. Once this C# library has been created, how can it be referenced from a simple Windows Forms Application or Service? I seem to be having issues with configuration when referencing the library which houses the Sink and Session.


Leave a comment

No trackbacks yet.