I've been investigating a bug that goes like this:
- Launch a background add-in under Windows 7
- Idle for a while (10-20 minutes); specifically, don't launch any media so that MediaExperience and MediaTransport remain NULL. Feel free to poll MediaCenterEnvironment.MediaExperience as much as you like.
- Start a video file playing
- Try and make it full-screen; it fails, because MediaExperience is still null, even though the media just started. From this point on, you can't access any MediaExperience/transport data until you restart Media Center. 100% repeatable.
The normal trick of polling MediaTransport doesn't help here, because there is nothing to poll -- it's NULL.
After doing some poking around the eHome assemblies, I found that the get_ property for MediaCenterEnvironment.MediaExperience uses a mini cache to avoid serving up a fresh MBRO-based object every time. I would guess it expects to get a PropertyChanged event from the remote MediaCenterEnvironment MBRO to let it know when MediaExperience changes -- but when this times out, the notification never arrives so the cache never gets flushed.
I did a little bit of cheating with reflection to force the cache to empty. For the benefit of anyone else who has been beating their head against this same problem, here's the code I used.
At the risk of stating the obvious: DO NOT USE THIS CODE UNLESS (a) YOU HAVE THIS SAME PROBLEM, and (b) YOU FULLY UNDERSTAND THE IMPLICATIONS. It is version-specific, likely to break on a future version of MCE (or maybe even a Windows Update) and is definitely not going to be supported in any way by Microsoft.
On the other hand, my persistent crash is now gone, and things are working very nicely. If anyone can provide a better workaround, I'm all ears!
public static void ResetMediaExperienceCache()
{
if (IsWindows7)
{
try
{
FieldInfo fi_single = AddInHost.Current.MediaCenterEnvironment.GetType().GetField("_checkedMediaExperience", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
if (fi_single != null)
fi_single.SetValue(AddInHost.Current.MediaCenterEnvironment, false);
else
Debug.WriteLine("Warning: cannot find MediaCenterEnvironment._checkedMediaExperience field on Windows 7");
}
catch (Exception e)
{
Debug.WriteLine("Error setting MediaCenterEnvironment._checkedMediaExperience flag on Windows 7: " + e.ToString());
}
}
}
static public MediaExperience CurrentMediaExperience
{
get
{
MediaCenterEnvironment env = AddInHost.Current.MediaCenterEnvironment;
if (env != null)
{
MediaExperience exp = env.MediaExperience;
if (exp == null)
{
// Reset experience cache under Windows 7 and try again
ResetMediaExperienceCache();
exp = env.MediaExperience;
}
return exp;
}
return (null);
}
}
I then reference CurrentMediaExperience from my own code, rather than MediaCenterEnvironment.MediaExperience. In addition, just to be safe, I do an explicit call to ResetMediaExperienceCache() immediately after any PlayMedia() call, to ensure that I am always using the most up-to-date object.
(The usual MediaTransport polling rules still apply.)