Licensing with IClassFactory2

A monumental problem for most software vendors is piracy—people making copies of software on multiple machines without any payment to the vendor. As more and more components become available, end users will find more opportunities to make illicit copies of those components, perhaps thinking that it's no big deal to copy just a little control or some other small component. People who would not copy a $500 word processor might not be so ethical when it comes to a $5 component, just as people today seem to have no qualms about copying a few fonts between systems. In such an environment it becomes necessary to control illegal copies.

To that end, COM supports a licensing mechanism that a server can use to control instantiations of its components. This involves differentiating between two scenarios:

License control means that you must have either global permission to use a component on a given machine or specific permission (the license key) to use the component on another machine.

The first scenario has been employed for some time to control application licensing and works just as well for components. The mechanism is trivial and requires no special operating system support. This is often achieved by having the installation program create some sort of license information on the machine. When the application is loaded, it checks for the presence of this information. If the information is not present, the application automatically terminates with a message politely telling the end user how to order a real copy of that application.

The second scenario is a little more complicated and comes into consideration only when applications are being developed using third-party components, such as custom controls and run-time libraries. The development machine itself is fully licensed because the developer had to purchase all those components and in doing so obtained the necessary licenses. However, any application created on that machine must be portable to other unlicensed machines along with the components, and it must take along with it the necessary permissions to use those components on the other machines. Even though the component server exists on the other machines, other clients are not allowed to use it because global license permissions do not exist. This is called run-time licensing.

The license key is the piece of information that an application must carry to other machines in order to continue using a component. When the final build of that application is generated, the development tool in use must request a license key from each component in use and save it so that the application can use it later. This key doesn't need to be anything fancy—a simple piece of text will prevent all but the most clever of end users from using illegal copies.

The heart of licensing in COM is the IClassFactory2 interface, which is a modest enhancement of IClassFactory.2 Because this interface is derived from IClassFactory, a server needs only to implement IClassFactory2 to satisfy all of COM's class factory requirements:


interface IClassFactory2 : IClassFactory
{
HRESULT GetLicInfo(LPLICINFO pLicInfo);
HRESULT RequestLicKey(DWORD dwResrved, BSTR FAR* pbstrKey);
HRESULT CreateInstanceLic(IUnknown *pUnkOuter
, IUnknown *pUnkReserved, REFIID riid, BSTR bstrKey
, void **ppvObject);
};

The GetLicInfo member function fills a LICINFO structure that describes available license information for this particular component:


typedef struct tagLICINFO
{
long cbLicInfo;
BOOL fRuntimeKeyAvail;
BOOL fLicVerified;
} LICINFO;

The fLicVerified flag indicates whether the component has a global license on the machine. This is another way of saying whether IClassFactory[2]::CreateInstance has any chance of succeeding on this machine. If the flag is FALSE, CreateInstance should return CLASS_E_NOTLICENSED; if TRUE, CreateInstance should work as usual.

The fRuntimeKeyAvail flag indicates whether the RequestLicKey function will succeed, for it is through this function that a client requests a license key that it can take to another machine in order to continue using the component. This key is returned in the form of a BSTR (introduced in Chapter 3 on page 173), which may, of course, contain encrypted information. This string, in any case, is exactly what a run-time licensed client would store persistently and take to another machine along with the component server.

Now, when that client is run on another machine, any call to CreateInstance will fail outright unless a global license also exists there. In the case of failure, the client can instead instantiate an object through CreateInstanceLic, using the license key. The class factory validates this key and, if it checks out, proceeds to create the object as if a global license is present. If the key fails validation, the class factory returns CLASS_E_NOTLICENSED. Thus, only a client with a proper license key from a proper installation can hope to instantiate an object from this component on an unlicensed machine.

As a component vendor, you are free to choose as secure a mechanism as you want. Microsoft's scheme is simple: the license file is a simple text file installed with the component itself, and a license key is usually nothing more than the first line of text from that file. This stops end users from making casual copies of a component, but it is fairly weak because you need only to copy the license file as well. A more secure scheme would involve something like additional registry entries, which would make it more difficult for an end user to know how to make a copy. You can go further and incorporate unique installation identifiers and encrypted information. The more devices you employ, the fewer end users will find out how to make and use illegal copies of your software. Whatever your security measures, COM and IClassFactory are there to help you validate them at run time.

2 Licensing was first provided with OLE Controls so you'll find this interface and associated definitions in OLECTL.H.