DRM Individualization with Windows Media Player and Windows Presentation Framework, Coding Approach

Jun 25, 2012
Oshyn Labs

Part 1

Due to the lack of good examples about how to create a portable component that performs the individualization on a computer I use the best example I’ve found, I mean the Microsoft web pages that mainly it demonstrates that it works and also I have the necessary logic make it work in a C# component, using this idea one of the things I’m playing with is wrap the logic of the above pages in the component that executes the individualization on demand. As you can infer the very first step you require to do this is to identify the involved components in the individualization stuff.


Hence the idea is to recreate the functionality provided by Microsoft through their individualization web pages it means it is necessitate to put the JavaScript functionality in a WPF application that will use the interop object MSNETOBJLib to get things like the DRMVersion or DRMSecurityVersion. The interop objects AxWMPLib and WMPLib are used like the player.

These objects are initialized as follows:

AxWindowsMediaPlayer Player;      

IRMGetLicense netobj = new RMGetLicense();


With the right components it’s important to identify the things to do, the first thing to do is to check the player version, it mainly allows identifying if it is possible to perform the individualization or if the individualization it’s not supported, this is possible evaluating the content of the version as in the code bellow.

void CheckPlayerVersion(bool bForceIndivit)

{

// If this is 7.0 player - pre-deliver a v7 license to work around bug which make  

// system in bad state

    // if the client machine individulized before any v7 license acquired.

    string version = netobj.GetDRMVersion();           

    string[] versionArray = version.Split('.');

 

    if (Convert.ToInt16(versionArray[0]) <= 7 &&

        Convert.ToInt16(versionArray[1]) < 1)

    {

        UpgradeNotSupported();

    }

    else

    {

        BeginIndiv(bForceIndivit);

    }

}


If the individualization is supported, one of the things we need is to determine the client version that will be used to properly download the right version of the security upgrade for that computer, the logic to this is described in the following code.

int GetClientVersion()

{

    string version = netobj.GetDRMVersion();

    string[] versionArray = version.Split('.');

 

    if ((Convert.ToInt16(versionArray[0]) == 9 &&

         Convert.ToInt16(versionArray[3]) > 3286) ||

        (Convert.ToInt16(versionArray[0]) == 10 &&

         Convert.ToInt16(versionArray[3]) > 3801))

    {

        // Corona, Crescent

        return 1;

    }

 

    if (Convert.ToInt16(versionArray[0]) > 10 &&

        Convert.ToInt16(versionArray[2]) == 0)

    {

        // Emerald

        return 2;

    }

 

    if (Convert.ToInt16(versionArray[0]) > 10 &&

        Convert.ToInt16(versionArray[2]) > 0)

    {

        // Polaris, Vista

        return 3;

    }

 

    // Old client.

    return 0;

}


Once we get the client version we can use this value to determine which is the right resource to be downloaded to perform the security upgrade, in other words to fires up the individualization as follows.

void BeginIndiv(bool isForced)

{

    Player.settings.autoStart = false;

    int clientVersion = GetClientVersion();

 

    if (isForced)

    {

        Player.URL = "http://go.microsoft.com/fwlink/?LinkId=49282";

    }

    else

    {

        switch (clientVersion)

        {

            case 0:

                // old client                                       

                Player.URL =

                    "http://go.microsoft.com/fwlink/?LinkId=49286";

                break;

 

            case 1:

                // Corona, Crescent

                Player.URL =

                    "http://go.microsoft.com/fwlink/?LinkId=49287";

                break;

 

            case 2:

                // Emerald              

                Player.URL =

                    "http://go.microsoft.com/fwlink/?LinkId=49288";

                break;

 

            case 3:

                // Polaris, Vista

                Player.URL =

                    "http://go.microsoft.com/fwlink/?LinkId=73923";

                break;

        }

    }

 

    Player.Ctlcontrols.play();

}


The handler used to treat at detail the security upgrade, basically it uses the event handler OpenStateChange from the player to check it up every state and accordingly to it perfom the individualization per ce, it goes as follows.

private void LayoutRoot_Loaded(object sender, RoutedEventArgs e)

{

    try

    {

        Player = windowsFormsHost.Child as AxWindowsMediaPlayer;

        Player.Ctlenabled = false;

        Player.Visible = false;

        Player.URL = string.Empty;

        Player.settings.rate = 1;

        Player.settings.balance = 0;

        Player.settings.defaultFrame = string.Empty;

        Player.settings.playCount = 1;

        Player.settings.baseURL = string.Empty;

        Player.settings.volume = 50;

        Player.settings.mute = false;

        Player.Ctlcontrols.currentPosition = 0;

 

        Player.OpenStateChange += (_sender, stateEventArg) =>

        {

            // The following script block is how we handle notification

            // events in JScript in IE.

            // This is the handler for the openStateChange notification. 

            // This notification will let us know when the player changes

            // state.  The states that we are interested in are

            // BeginIndividualization, EndIndividualization,

            // BeginLicenseAcquisition, and EndLicenseAcquisition

            var statemap = new string[] {"Undefined",

                            "PlaylistChanging",

                            "PlaylistLocating",

                            "PlaylistConnecting",

                            "PlaylistLoading",

                            "PlaylistOpening",

                            "PlaylistOpenNoMedia",

                            "PlaylistChanged",

                            "MediaChanging",

                            "MediaLocating",

                            "MediaConnecting",

                            "MediaLoading",

                            "MediaOpening",

                            "MediaOpen",

                            "BeginCodecAcquisition",

                            "EndCodecAcquisition",

                            "BeginLicenseAcquisition",

                            "EndLicenseAcquisition",

                            "BeginIndividualization",

                            "EndIndividualization",

                            "MediaWaiting",

                            "OpeningUnknownURL"};

 

 

            var state = stateEventArg.newState;

            var initializationStarted = false;

 

            if (statemap[state] == "BeginIndividualization")

            {

                //This block is executed if Individualization has begun.

                //(This is after the user clicks OK

                //on the pop-up indiv dialog.

                initializationStarted = true;

            }

            else if (statemap[state] == "EndIndividualization")

            {

                //Individualization has ended.  Assume it passed because

                //the error event wasn't hit.

                UpgradeCompleted();

            }

            else if (statemap[state] == "BeginLicenseAcquisition")

            {

                // Now that we are individualized we have to

                // acquire a license.

                // set the state to no license

                // TODO: Complete these lines.

                bHaveLicense = "nolic";

                UpgradeCompleted();

            }

            else if (statemap[state] == "EndLicenseAcquisition")

            {

 

                //License acquisition passed successfully.

                // TODO: Complete these lines.

                bHaveLicense = "havelic";

                // I assume at this point there should be no errors.

                UpgradeCompleted();

            }

            else if (statemap[state] == "MediaOpen")

            {

                switch (bHaveLicense)

                {

                    case "uninit":    //We have this state if the

                        //user *already* had a license.

                        bPassed = true;

                        break;

                    case "havelic":

                        //We have individualized and acquired a license.

                        //The content will now try to play. 

                        //Just tell it to stop, and close the Player.

                        bPassed = true;

                        break;

                    case "nolic":

                        //We tried to acquire a license but failed....

                        //We don't care if license acquisition fail

                        //or not.       

                        bPassed = true;

                        break;

                }

 

                UpgradeCompleted();

            }

        };

 

 

        bFilePlayed = true;

        Init(false);               

    }

    catch (Exception ex)

    {                 

        this.Close();

    }

}

There are two additional pieces of code, the first one is used when the security upgrade is not supported and basically it closes the WPF application.

void UpgradeNotSupported()

{

   

    // If the upgrade is not supported this window will

    // be closed automatically.

    this.Close();

}

The second one is executed when the security upgrade is completed and also it closes the WPF application.

void UpgradeCompleted()

{

    if (bProcessCompleted)

    {

        return;

    }

 

    bProcessCompleted = true;       // set the flag

    Player.Ctlcontrols.stop();      // stop individualization,

                                    // since this is forced update

    Player.close();

}