Pages

Advertisement

Thursday, July 12, 2007

Licensed Applications using the .NET Framework

Ah, but that's the catch. If you stop to consider the financial aspects of writing software, the plain truth is that while we may do this work because we enjoy it, we all have families to feed, bills to pay, and frankly we all like to go on holiday from time to time. It's not an unfair observation, after all, and people using our software probably feel the same way about their careers. They work and want to be compensated for their efforts, even if secretly they love what they're doing and would work at it anyway.

The problem is that software is often a nebulous thing when given to an end user. All they see is the application itself, and even then it only exists for a moment in time as electrical charges in their computer's memory. That hardly seems like a product that took hundreds or thousands of hours to develop and test, or at least is not physically comparable to objects such as a car or a refrigerator. Honest, hardworking computer users that would never consider stealing a car or a refrigerator often think nothing of trading software with friends, and oftentimes they even know this is against the licensing agreements that came with the software. But the software is just bits on a CD, right? What harm can it be to hand that software to their brother or friend?

Well, you know the answer to that! That's one user that didn't pay you for your hard work. In business terms you lost revenue. If you lose enough revenue, as a business you go out of business. As an individual, you can't meet your financial obligations (all those bills you pay), so you either work at a fast food chain to make ends meet or you declare bankruptcy and live in a cardboard box under a freeway overpass. Personally, I'd rather make sure that user pays for the application and ultimately my hard work to design, develop, test, market, and distribute the software I wrote.

The solution is software licensing. As an industry, many people have tried to solve this problem in various ways. In the past software was sold on copy-proof media (remember the floppy disks with the extra track?). These days you often have to enter some sort of software key to enable crippled software packages. Microsoft recently began online Internet-based software authorization with their high-end operating systems and products (such as Office, probably the most often pirated piece of software ever written). Within the .NET Framework, there also exist the nuggets of technology you can use to license your applications, and that's what I'd like to show you now.

Control Licensing

Nearly everything you'll read about .NET licensing binds the licensing concept to controls, with the idea being control developers could ship controls that are licensed at design time and/or run time. As it happens, you can apply Framework licensing to any class derived from System.Windows.Forms.Control, which would include entire Windows Forms applications, but I'll begin with controls themselves. The basic control licensing UML static class diagram is shown in Figure 1.

Figure 1. .NET Control Licensing Static Class Diagram.

The general execution sequence is shown (as a UML sequence diagram) in Figure 2. The licensed control, in its constructor, requests a license from the LicenseManager:

license = LicenseManager.Validate(typeof(MyLicensedControl), this);

In this case, the constructor is for the licensed control as implemented in the class MyLicensedControl. Interestingly, there may be nothing more you need to do with the license object itself (it depends upon the implementation of the license), except to properly dispose of it as there may be resources attached. Out of the box, the important action we took was to call the license manager and ask for a license. If a license is not to be granted for some reason, the Validate() call will fail with an exception if exceptions are desired or return a null license if exceptions are to be suppressed. (The call to LicenseProvider.GetLicense() controls this, and the default Framework implementation is to allow exceptions.)


Figure 2. Control Licensing Sequence.,/p>

The license manager, in turn, calls the control's license provider's GetLicense() method. And how does the license manager, a .NET Framework component, know which license provider is to be used? After all, you provide the license provider... The answer is through metadata in the traditional .NET way, via attribute:

[LicenseProvider(typeof(MyLicenseProvider))]
public class MyLicensedControl : System.Windows.Forms.Control
{
...
}

The license manager looks for the LicenseProvider attribute attached to the licensed control class. Since the LicenseProvider attribute takes the type of the license provider as input to its constructor, the license manager can reflect this information when asked to validate the license. Your license provider must be derived from the LicenseProvider class and must override GetLicense(), an abstract method (MustOverride for the Visual Basic fans):

public class MyLicenseProvider :
System.ComponentModel.LicenseProvider
{
...

public override License GetLicense(
LicenseContext context,
Type type,
object instance,
bool allowExceptions)
{
...
}
}

The magic within .NET that allows for licensing consists of the process I just described. But in the end, the real licensing magic is encoded within the GetLicense() method. Before we get too imaginative ourselves, you should know that Microsoft ships with the Framework a rudimentary license provider called LicFileLicenseProvider. While I believe that for completeness I should describe how you use LicFileLicenseProvider, I also believe that anyone serious about licensing their software will most likely avoid such a simple scheme in favor of their own, more creative schemes, one of which I'll introduce to you after describing LicFileLicenseProvider.

LicFileLicenseProvider

The premise behind LicFileLicenseProvider is simple—it checks for the existence of a license file, and if the file exists, it checks the file contents for validity. The file may physically reside on the disk with the application, or it may be encoded as an application resource if you write some additional code to dig it out. If the file exists and has valid contents, the license provider issues a license to the license manager and ultimately to the control. If not, the license provider will throw a LicenseException and your control should then choke and die.

LicFileLicenseProvider overrides GetLicense(), as it must, but it also provides two additional virtual methods, IsKeyValid() and GetKey(). If you use LicFileLicenseProvider as it's implemented in the Framework, GetKey() will look for a file in the assembly's execution directory named {full name}.lic, where {full name} is the full type name of the licensed control class, typically {assembly name}.{class name}. If the assembly MyControlAssembly exposed the licensed control I've been using in my example thus far, the license file would be in the file named:

MyControlAssembly.MyLicensedControl.lic

With the contents of the file in hand, IsKeyValid() compares the file contents with the string "{licensed class} is a licensed component." (period included). For my example, the file MyControlAssembly.MyLicensedControl.lic would contain the string "MyControlAssembly.MyLicensedControl is a licensed component." If the license file is missing, or if the contents are incorrect in any way, the validation fails and the control should fail to instantiate. I've included with downloadable samples solution an example that has a licensed version of the MSDN sample color-picker ComboBox control.

Since IsKeyValid() and GetKey() are virtual, you can easily derive a new class that looks elsewhere for the license file or validates against a different string (perhaps one that's encrypted or one that simply uses a different phrase). A "good" implementation, however, would still deal basically with license files since the base class exposes such functionality. If you would rather implement a totally different licensing scheme, it's a better design choice to derive a license provider directly from LicenseProvider. Since I believe we can be a bit cleverer, I'm not going to provide an example of a derived license file provider. Instead, I'll describe some alternative licensing schemes...

Compiling License Files

Before I leave license files entirely, I should mention lc.exe. lc.exe, or the license compiler, is a tool that ships with the .NET Framework that will take license file information and encode that as an assembly resource. It's an odd addition to the tools provided by the Framework since the default implementation of LicFileLicenseProvider doesn't look for a resource-based license file, but it does have some interesting flexibility. For one thing, it's an easy way to generate the resource information. But more interesting is its ability to encode multiple license files into a single resource, allowing you to license several controls with differing license file strings at once. A significant limitation in my view is the fact that you must use the assembly linker (al.exe) to assemble your compiled modules and resources. For the command-line lovers, that's no problem. But for those of us that develop using Visual Studio .NET, it's a limitation since Visual Studio .NET doesn't compile or generate multi-module assemblies (although you could embed the resource output into your project file with a build action of "embedded resource").

Speaking of Visual Studio .NET, if you want to create a licensed control, you'll find no automated support in either version of Visual Studio (2002 or 2003). So how do you create licensed controls? The answer is you simply create the file manually and ship it with the compiled assembly. Personally, I add the file to my Visual Studio project with a build action of "none," but there is no requirement to do so. It merely makes source code control somewhat easier as the file can be rolled into my source repository along with the other project/solution files. I still have to manually copy the file to the assembly execution directory.

Alternative Licensing Schemes

I believe Microsoft was obligated to provide a default license provider for the .NET Framework, and they chose to implement one that works very similarly to the licensing for ActiveX controls. But I also believe Microsoft has no intention of using such a simplistic licensing scheme for any of their production software (or at least not for anything significant). Instead, why not provide a licensing scheme that's easier to ship, more clever, harder to break, or whatever? And that's where alternative licensing schemes come in.

You could license your control nearly any way you like. Perhaps you can only design with it on Tuesdays, or you can only execute the control in an application if the weather report for the user's local area is sunny (i.e.: accept the user's postal code and download the weather report from the Internet). I'm actually not joking. You could do these things... That doesn't mean you should, but the licensing process is flexible enough to do so. I'm going to show a more realistic approach, that being a Registry license key. But before I describe this scheme in detail, there is a fact with which you should be aware:

.NET Windows Forms applications are derived from System.Windows.Forms.Form, which is in turn derived from System.Windows.Forms.Control!

Wait a minute... That means, what? Well, what that means is you can license an entire application just as easily as licensing a control. And though the scheme I'll show you targets application licensing versus control licensing, it could apply to both situations. Let's think about the implications of this for a moment.

Application versus Control Licensing

The basic difference between application and control licensing is when you really care about the license. If you develop controls and components for a living, your target market would consist of other software developers. That means your licensing scheme checks for the insertion of a control into a Visual Studio project at design time. Since you probably want to make a few million selling your control library, you'll naturally offer the runtime license for free, or most likely not impose a runtime license at all. After all, you want your target market to sell applications like crazy so they'll buy more controls from you.

Application licensing, however, is different. With applications, we, ourselves, are building the application at design time. It makes no sense to impose any sort of design time license upon ourselves. Rather, we want to make sure the user has the appropriate licensing information in place at run time.

The Framework designers took this into account when they designed the licensing architecture, and you can check for the state of the license request, design time or run time, when the call to GetLicense() is made. I'll actually show both cases, but the only time I'll worry about validating a license is at run time, since I'm showing how applications may be licensed rather than merely licensing controls. It's an important distinction, however, and one you should be aware of.

Registry-Based Licensing

Registry-Based licensing implements a licensing scheme that checks for the presence of a specific Registry key that contains a specific value. The application itself implements no code to write the Registry value--that must be done by the installation application, and since most applications use the Registry anyway, this doesn't pose a significant development limitation. We've been pre-populating Registry keys with our installation applications ever since there was a Registry.

I could, if I wanted, be cleverer regarding the value written to the Registry, but for this example I'll simply write the string "Installed." I'll leave the more clever implementations to you (hey, I can't give away all of my secrets!). The value I'll look for is this:

HKEY_CURRENT_USER\Software\Acme\HostKeys\2de915e1-df71-
3443-9f4d-32259c92ced2

The GUID value you see is a GUID I assigned to my application. Each application Acme Software sells has its own GUID, but through reflection I can use the same license provider for all applications. Ah, the power of .NET at work... I'll stuff all Acme Software license keys here, hence the key name "HostKeys." In your own applications, feel free to shove the key anywhere that is appropriate.

The application is very simple, as you can see from Figure 3.


Figure 3. The Registry-Licensed Application.

If you see this window, the license was valid. On the other hand, if the license was invalid, you'd see the exception dialog you see in Figure 4.


Figure 4. Invalid Registry License Response.

To make this work, we'll need to create a new application and modify the wizard-generated code slightly. By the way, I don't mean ignore the Visual Basic programmers amongst us... The example files contain identical C# and Visual Basic .NET applications. The program code shown here is C#, but the translation is very straightforward.

To begin, we'll need to modify the source code for the main application in four places in addition to writing our own license provider. These four areas are:


  1. The application class declaration (to add some attributes)
  2. The application class constructor
  3. The application class Dispose() method
  4. The application "main" method

I'll also add a using clause since I will employ the GuidAttribute. Let's look first at the class declaration:

/// <summary>
/// Summary description for frmMain.
/// </summary>
[GuidAttribute("2de915e1-df71-3443-9f4d-32259c92ced2")]
[LicenseProvider(typeof(RegistryLicenseProvider))]
public class frmMain : System.Windows.Forms.Form
{
...
}

To the class I've added two attributes: GuidAttribute and LicenseProvider. LicenseProvider you've seen, but the purpose of GuidAttribute is to assign a GUID, or a unique numerical value, to this application class. Normally this attribute is used for COM interop, but I'll reuse it here simply to assign the application class a unique numerical identifier that has existing Framework support (that is, we can easily determine the class type's GUID later). I could have generated my own attribute, but then I lose the built-in Framework GUID detection support. It's also important to note that the GUID value I assigned to GuidAttribute matches the GUID value I used as the Registry key. This is the value my license provider will reflect to generate this application's Registry license key value. Because I used GuidAttribute, I had to add this to my collection of namespaces:

using System.Runtime.InteropServices;

To the application class constructor, I add the code you've seen previously:

private License _license = null;

public frmMain()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();

// Obtain the license
_license = LicenseManager.Validate(typeof(frmMain), this);

}

Here I simply call the license manager's Validate() method—nothing special. However, the Validate() method could throw an exception if the license is invalid. Therefore it's a good idea to catch this exception somewhere. But also notice that I added a private data member called _license. Some licensing schemes could make use of this license object (I do not in this example), but in all cases I'll need to dispose of that license when the application terminates. There may be resources assigned to the license that should be released properly. Therefore, I had to modify the application's Dispose() method:

/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}

if (license != null)
{
license.Dispose();
license = null;
}
}

base.Dispose( disposing );
}

Here, I just do a quick check for a null license, and if it's not null, I call its Dispose() method and null its reference. Even though in this example I don't use the license, this is required because the license could have resources it must release.

Finally, I modified the applications Main() method to take the license manager's exception into account:

/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
// Create an instance of the licensed application
frmMain app = null;
try
{
// This will throw a LicenseException if the
// license is invalid... if we get an exception,
// "app" will remain null and the Run() method
// (below) will not be executed...
app = new frmMain();
} // try
catch (Exception ex)
{
// Catch any error, but especially licensing errors...
string strErr =
String.Format("Error executing application: '{0}'",
ex.Message);
MessageBox.Show( strErr,
"RegistryLicensedApplication Error",
MessageBoxButtons.OK,
MessageBoxIcon.Error);
} // catch

if ( app != null ) Application.Run(app);
}

The Registry License Provider

As I mentioned previously, the bulk of the license validation is done in your license provider's GetLicense() method. Here is the code for my Registry license provider (found in the examples within the RegistryLicenseProvider.cs source file):

public override License GetLicense(
LicenseContext context,
Type type,
object instance,
bool allowExceptions)
{
// We'll test for the usage mode...run time v. design time.
// Note we only check if run time...
if (context.UsageMode == LicenseUsageMode.Runtime)
{
// The Registry key we'll check
RegistryKey licenseKey =
Registry.CurrentUser.OpenSubKey("Software\\Acme\\HostKeys");

if ( licenseKey != null )
{
// Passed the first test, which is the existence of the
// Registry key itself. Now obtain the stored value
// associated with our app's GUID.
string strLic =
(string)licenseKey.GetValue(type.GUID.ToString()); // reflected!
if ( strLic != null )
{
// Passed the second test, which is some value
// exists that's associated with our app's GUID.
if ( String.Compare("Installed",strLic,false) == 0 )
{
// Got it...valid license...
return new RuntimeRegistryLicense(type);
} // if
} // if
} // if

// if we got this far, we failed the license test. We then
// check to see if exceptions are allowed, and if so, throw
// a new license exception...
if ( allowExceptions == true )
{
throw new LicenseException(type,
instance,
"Your license is invalid");
} // if

// Exceptions are not desired, so we'll simply return null.
return null;
} // if
else
{
return new DesigntimeRegistryLicense(type);
} // else
}

The interesting code begins where we check to see what mode we're currently executing within—design time or run time:

if (context.UsageMode == LicenseUsageMode.Runtime)
{
... // Run time mode
}
else
{
... // Design time mode
} // else

If we're operating at design time, we'll simply create and return an instance of our design time license object:

return new DesigntimeRegistryLicense(type);

However, if run time, we'll open our special Registry key and look for our application's GUID key/value pair. We open the Registry key like so:

RegistryKey licenseKey =
Registry.CurrentUser.OpenSubKey("Software\\Acme\\HostKeys");

And we generate the key by reflecting the application GUID from the object we're given (remember the GuidAttribute we placed on our licensed type?):

string strLic =
(string)licenseKey.GetValue(type.GUID.ToString());

The GetValue() method will either return the value associated with the key, or null, so we test for null and then check the returned value against the value we expect to see that represents a valid license:

if ( strLic != null )
{
// Passed the second test, which is some value
// exists that's associated with our app's GUID.
if ( String.Compare("Installed",strLic,false) == 0 )
{
// Got it...valid license...
return new RuntimeRegistryLicense(type);
} // if
} // if

If everything is fine, we return a new instance of our run time license object. If not, we check to see if exceptions are allowed, and if so, throw a new license exception:

if ( allowExceptions == true )
{
throw new LicenseException(type,
instance,
"Your license is invalid");
} // if

If exceptions aren't allowed, we simply return null.

The license classes in this case are identical, but there is no requirement that they be the same. The run time license is shown here:

public class RuntimeRegistryLicense : License
{
private Type type;

public RuntimeRegistryLicense(Type type)
{
if ( type == null )
throw new NullReferenceException(
"The licensed type reference may not be null.");
this.type = type;
}

public override string LicenseKey
{
get
{
// Simply return the application's GUID
return type.GUID.ToString();
}
}
public override void Dispose()
{
}
}

Since I derived a new license type from the base License class, I had to override the LicenseKey property (it's an abstract method). In doing so, I return the application GUID when asked. I could, however, re-evaluate the Registry or check for a timed expiration or some other invalidating condition.

More Exotic Licensing

The technique I've shown here is still fairly rudimentary. While many users couldn't open the Registry and find the key without significant assistance, still others are quite capable of breaking this scheme. There are other things you could do, however, that make it much more difficult to break your licensing arrangements.

The most obvious thing you could do is replace my simple "Installed" string with an expiration date and time (and encrypt the values as well). Or you could write even more complex license providers that call a Windows or Web Service to request permission to execute the application. I've written both and they're extremely effective. And as I mentioned, the license object itself could invalidate itself and force the application to shut down, given some invalidating criteria. Perhaps it checks a licensing Web Service or database to determine the application's daily license status. In any case be sure to obfuscate your production assemblies!

Conclusion

If you've read this far and studied the basic Framework licensing process, you may be wondering why I went to such lengths to work within the Framework. After all, couldn't I simply create my own licensing manager and process? Aren't there non-Framework like oddities in the licensing architecture, such as the boolean value passed into GetLicense() to enable exceptions? (I would expect an attribute or property assigned to the LicenseManger or licensed class rather than a boolean value passed to GetLicense()... there isn't any way I can see to change the default Framework behavior otherwise!)

I can only imagine that using the Framework's licensing architecture versus rolling your own will have benefit to you in the future. After all, you would be following the Framework's prescribed pattern, and changes to the Framework might be of consequence to you. You also would utilize some Framework components, thereby deriving reuse and saving some (albeit slight) maintenance costs.

As for licensing itself, though, the only limit is your own imagination. Now, go and collect that revenue you've been losing!

Download Source Code

Download source code: LicensedApps.zip - 76 kb

No comments:

Post a Comment