Chapter 26

Licensing and Distribution


CONTENTS

The computer business must be one of the oddest industries that has ever existed. There's the incredible and overwhelming rate of change we are all experiencing. And there is the enormous impact that computers are having on society, which I think we have only begun to experience. Those are perhaps subjects for another book. Right now I want to talk about money.

Sometimes I think we programmers have a love/hate relationship with money. On one hand there is an ongoing theme that information and software should be free. There are thousands of freeware and public domain applications out there, many of which are excellent. There are uncounted programmers who write great software just for the fun of it or for the principle involved. I'm hard pressed to think of any other industry where this is the case.

On the other hand, how many programmers do you know who are doing some software development "on the side" in the hope of ultimately founding the next Netscape or Microsoft? I know quite a few myself. (And no, I neither expect, nor want, to run the next Netscape or Microsoft.)

This dichotomy also appears during a typical development cycle. We tend to be perfectionists, looking for the most creative and elegant solution to software problems, preferring sometimes to write our own code rather than purchase someone else's. Yet there is also pressure to meet tight schedules and to find the most economical solution to the task at hand. The two forces are in perpetual conflict. So part of what we do as software developers is try to find a balance between the two.

I don't know to what degree today's computer science degree programs discuss this issue. I know the economics of a software project was not a large part of my curriculum when I was in school. However, at the same time as I was studying computer science, I also picked up an engineering degree. The economic implications of a project was a very strong theme in that program, even to the point of having a class dedicated to the subject. I must confess that this economics background has influenced the way I approach software development. Which brings us to the subject of software licensing.

The Purpose of Licensing

When I started this chapter, I tried to imagine the needs of the typical Visual Basic programmer with regard to licensing and distribution issues.

My background is that of an Independent Software Vendor (ISV) who develops and markets commercial controls. Up until Visual Basic 5.0, I had assumed that the vast majority of readers would have no intention of becoming control or component vendors. Authoring controls in Visual C++ is too difficult to attract large numbers of developers.

But Visual Basic 5.0 makes the development of ActiveX code components and controls easy. And there is a chance that large numbers of programmers will begin creating controls and ActiveX documents for the Internet. The question is simply this: If Visual Basic 5.0 makes it possible for anyone to create ActiveX components, will they? I will assume for now that the answer is yes.

This chapter is thus premised upon the idea that whether you are working for a large corporation or are an independent software developer or want to create commercial or shareware controls, you will have an interest in incorporating some licensing mechanism to protect your technology.

Degrees of Security

The first question you need to ask is how much security you require. There is a real trade-off here, since the more secure your component is, the harder it will be to use.

One could imagine a component that requires one of those hardware security devices or "dongles" that are attached to a parallel port. Imagine if every component vendor took this approach. A fairly complex program could require dozens of dongles chained to the back of each computer-a frightening thought.

Barring a hardware solution (and possibly including a hardware solution), it is probably impossible to come up with a 100 percent fail-safe licensing scheme. If there is one, I don't know about it.

The approaches you'll read about in this chapter do not claim to be perfect. In fact, they don't even claim to be secure. Instead, they follow the approach that has been adopted by both Microsoft and most component vendors, that component licensing exists to make it inconvenient to use components that are unlicensed. In other words, you distribute the control with a license agreement that threatens dire consequences if the license is violated. You include a simple licensing scheme that effectively warns users when they are about to violate the license. And then you ultimately trust them to be honest.

So each technique you will read about shortly is really more of a warning mechanism than a secure licensing mechanism. I will provide some suggestions that can help you improve the security of your licensing approach through use of hidden files or passwords, but they will not be the real focus of the chapter.

Licensing Models

The Visual Basic documentation discusses ActiveX control licensing at great length. But the approach it describes only covers one licensing model and does not cover ActiveX code components at all. What are licensing models? They represent different approaches to distributing components. Consider the following examples:

Design-Time Licensing. This is the model that is supported by Visual Basic for ActiveX controls and is frequently used by control vendors. Controls must be licensed in order to load within the container's design-time environment. Controls do not need to be licensed to work in the runtime environment. This approach is also supported by the ActiveX specification in the form of a special interface called IClassFactory2 that is built into every Visual Basic control to support licensing. The functioning of this interface is built into Visual Basic and is transparent to VB programmers.

License File/Component. This approach can be used with both controls and ActiveX DLL code components. It uses separate files or ActiveX components for licensing instead of adding license keys to the system registry.

Runtime Licensing. This approach uses a separate file or ActiveX component to provide licensing in all situations. It is used in cases where you wish to license runtime distribution of components as well as their design-time use. Runtime licensing is not common in the current market for Visual Basic add-on components. However, this approach may be useful for applications you intend to use on a corporate intranet to help prevent them from being distributed outside of your company.

Separate Demo Components. This model is especially useful for ActiveX code components. It consists of compiling separate demo components that either have limited functionality or only run when called within the context of certain development tools such as Visual Basic. This approach is designed to allow you to distribute demonstration versions of a control while controlling access to the release version.

Limited Duration Components. This approach involves enabling a control or ActiveX code component for a limited time period. After this period, it disables itself, perhaps until a unique password is provided.

Which of these approaches should you use? Other than the obvious fact that some of them can be used with code components and ActiveX documents, the decision is largely dependent on what it is that you are trying to accomplish. If you want to provide a mechanism for people to evaluate your controls, you might take the demo or limited duration approach. If you are only interested in limiting unauthorized use of your controls, you might choose one of the file or registry-based approaches. You can combine the approaches as needed.

ActiveX Control Licensing

Let us begin with a quick summary of the licensing approach supported directly by Visual Basic.

You can create a licensed control by selecting the Require License Key checkbox in the General tab of the Project Properties dialog box. When you do this, the following occurs:

Let's take a closer look at these issues.

Every licensed control supports an interface called IClassFactory2, which is used during the control's creation. This is a standard ActiveX interface designed specifically to support this type of licensing. The container that loads the control is required to pass it a license key, a unique string defined by the control. If the key that is provided by the container matches that of the control, the control loads successfully.

Where does this license key come from? Visual Basic pulls the key from one of two sources, depending on whether the container is in design time or runtime. If the container is in design time, Visual Basic looks in the registry for a license key for the control.

When a control is compiled into an application, Visual Basic stores the license keys for each control with the application. That way, when a control is loaded into the running application, Visual Basic can use the stored key and allow the control to run.

Controls built from constituent controls are handled the same way. Each of the constituent controls must load in order for the main control to run. When the control's container is in design mode, Visual Basic attempts to find a license key for each constituent control. If any of the constituent controls are licensed and a license key cannot be found, the control will fail to load. By the same token, when a control is compiled into an application, Visual Basic stores the license key for each of the constituent controls with the application so it can create them at runtime.

This means that if you use licensed constituent controls in your controls, you must distribute license keys for each of the constituent controls for your control to be usable at design time. Naturally, you should never distribute a license key unless you have the right to do so. You'll have to contact the vendors of any components you use to obtain the right to use them.

License keys are stored in the registry under the HKEY_CLASSES_ROOT\Licenses key. Let's say that you create a control called xyz.ocx with GUID:

93A7C69D-7FEE-11D0-93A6-00AA0036005A.

When you create the project, a VBL file is created that might look something like this:

Key Name:          Licenses\93A7C69D-7FEE-11D0-93A6-00AA0036005A
Class Name:        <NO CLASS>
Last Write Time:   2/5/97 - 11:01 PM
Value 0
  Name:            <NO NAME>
  Type:            REG_SZ
  Data:            onmghnnglnlgpgknsmmnmnlnomrhgnigtnth

This VBL file contains instructions for registering the license key and the key itself-typically a random string of data. This GUID will appear as a subkey in the registry as follows:

HKEY_CLASSES_ROOT\Licenses\93A7C69D-7FEE-11D0-93A6-00AA0036005A =
 onmghnnglnlgpgknsmmnmnlnomrhgnigtnth

The Visual Basic setup wizard uses the VBL file to add licensing registration instructions to the setup program. When you run the setup program, it will add the license key to the registry. If someone just copies the control onto their system, it will work fine with applications; they will have the license key compiled into the application itself. But if a user tries to place or load the control on a Visual Basic form at design time, Visual Basic will fail to find the license key and will not load the control.

This approach has one major limitation: it does not help you with environments that do not have separate design-time and stand-alone runtime modes. For example: Microsoft Office applications always check the registry for a license key. This means that if you want your control to be usable within Office applications, you must always provide the license key, which is effectively the same as providing no licensing at all. ActiveX documents are also not able to store license keys. Thus, they also check the registry for license keys any time a control is loaded. An alternative approach that allows additional control over licensed environments will be described shortly.

A slight variation of the control licensing approach described here relates to using controls on Web pages. Clearly these controls require license keys to work. It's also clear that registering license keys for each control that is downloaded would not be acceptable. It would be the equivalent of providing an unlimited license for the use of each downloaded control. Including the key on the Web page itself would make accessing the key just a little bit too easy.

Thus, browsers that support ActiveX controls provide a mechanism to download a license package file, or .LPK file. This file is created using a program called lpk_tool.exe, which can be found in the Tools directory on your Visual Basic CD-ROM. This program allows you to combine the license keys for all of the controls on a Web page into a file with the extension .LPK. You can then add a parameter to the Object tag of the Web page as follows:

<PARAM NAME="LPKPath" VALUE = "mylpk.lpk">

This adds to the object a special parameter named LPKPath, which tells the browser the name of the .LPK file to retrieve. This file name should be relative to the page and not an absolute URL, to make it more difficult to copy pages and run them on your local system.

Why do you have to use a special tool to create the license package file? Why can't Visual Basic do it for you? Because the file must contain the license keys for every control on a Web page and Visual Basic cannot possibly know which controls will be on a particular page. The license keys provided in this file are only used by the browser to load the controls. They are not added to the registry.

Alternative Licensing Approaches

You've seen that the standard control licensing approach does not work well with containers that always use the registry for license keys. It also does not help with regard to licensing ActiveX documents and ActiveX code components. I'll address both of these issues in a moment. But first, let's take a look at how to implement a demonstration component. The techniques used to do this are a good introduction to those used in other control licensing schemes.

Creating Demonstration Components

The gtpDT.vbg program group demonstrates an alternative approach for licensing. The gtpLicDT.vbp and gtpLicRT.vbp projects both expose a class named gtpLicensed, which contains the following code:

Option Explicit

Public Sub A()
   ' Prevent key functionality
   If Not VerifyLicense() Then
      MsgBox "License failure won't allow this operation"
      Exit Sub
   End If
   MsgBox "Subroutine A was invoked"
End Sub

Private Sub Class_Initialize()
   MsgBox "gtpLicensed object created"
End Sub

In this example, the functionality of function A is blocked if a license test fails. You could take a more extreme approach and raise an error, possibly during the class initialization, if the licensing fails. Normally, you should never raise arbitrary errors in a code component, but in this case you probably won't mind if the application fails in an unpleasant manner. Just be sure to first bring up a message box or dialog explaining the problem so the end user will not spend hours trying to figure out what is wrong.

The VerifyLicense function can be found in module Licenser.bas that contains the following code:

' Guide to the Perplexed
' Copyright © 1997 by Desaware Inc. All Rights Reserved

' Options supported by this module include:
' DEMOVERSION - Verifies ok in VB environment only
' DLLCHECK - Requires license file in VB environment


Option Explicit

Private Declare Function GetModuleFileName Lib "kernel32" Alias "GetModuleFileNameA"
(ByVal hModule As Long, ByVal lpFileName As String, ByVal_ nSize As Long) As Long
Private Declare Function GetModuleHandle Lib "kernel32" Alias "GetModuleHandleA"
_ (ByVal lpModuleName As Long) As Long

#If DEMOVERSION Or DLLCHECK Then
' Return True if
' The demo can run on any VB platform, design
' or runtime
Public Function IsVBEnvironment() As Boolean
   Dim thismod&
   Dim thisfile$
   Dim basename$
   Dim thispos%
   Dim thischar$

   On Error GoTo nogo
   thismod = GetModuleHandle(0)
   thisfile = String$(262, Chr$(0))
   Call GetModuleFileName(thismod, thisfile, 261)
   thisfile = Left$(thisfile, InStr(thisfile, Chr$(0)) - 1)
   thispos = Len(thisfile)
   Do
      thischar = Mid$(thisfile, thispos, 1)
      If thischar = "\" Or thischar = ":" Then Exit Do
      thispos = thispos - 1
   Loop While thispos > 0
   basename = LCase$(Mid$(thisfile, thispos + 1))
   If basename = "vb.exe" Or basename = "vb32.exe" Or _
      basename = "vb5.exe" Then
         IsVBEnvironment = True
   End If
   Exit Function
nogo:
End Function
#End If

Public Function VerifyLicense() As Boolean
   Static PriorVerification As Boolean
   Static VerifiedOnce As Boolean
   ' Fast return 2nd time through
   If PriorVerification Then
      VerifyLicense = VerifiedOnce
      Exit Function
   End If
   PriorVerification = True
   #If DEMOVERSION Then
      If Not IsVBEnvironment() Then
         ' License failure screen
         frmAbout.MessageType = 1
         frmAbout.Show vbModal
         VerifiedOnce = False
      Else
         ' Optional splash screen
         frmAbout.MessageType = 0
         frmAbout.Show vbModal
         VerifiedOnce = True
      End If
      VerifyLicense = VerifiedOnce
      Exit Function
   #End If
   #If DLLCHECK Then
      If IsVBEnvironment Then
         ' Check for DLL or object here.
         ' If not found, Set VerifyLicense to False
         VerifiedOnce = False
      Else
         VerifiedOnce = True
      End If
      VerifyLicense = VerifiedOnce
      Exit Function
   #End If
   VerifiedOnce = True    ' Default ok
   VerifyLicense = True
End Function

The behavior of this module depends on two conditional compilation constants. For now, we'll look at the DEMOVERSION constant.

ActiveX components cannot detect the difference between design time and runtime. The DEMOVERSION conditional compilation constant is intended to allow you to compile two versions of a component easily: one that always runs, the other that only works within the Visual Basic environment.

When this constant and the DLLCHECK constant (which will be described later) is undefined or is 0, the VerifyLicense function always returns True. This provides a very fast verification for the regular component. When the constant is True, the VerifyLicense function first calls the IsVBEnvironment function to see if the current process is Visual Basic. It does this by using the GetModuleHandle function with a null parameter to retrieve the instance handle of the running application. The GetModuleFileName function can then be used to retrieve the name of the executable file for the application. If it is one of the possible Visual Basic executable names, the function returns True, indicating that the component is running under Visual Basic.

Naturally, you can extend the list to include any applications you wish. You can even use a separate file or set of registry entries to indicate which applications the demo component is allowed to run in.

The VerifyLicense function performs the verification only once. From then on, it returns the results of the initial test. This serves two purposes. First, it improves efficiency. Second, it makes it easy to support a splash screen that will appear only on first load of the DLL.

The first time VerifyLicense is called, the frmAbout form is shown. The code for this form is shown below:

' Guide to the Perplexed
' Licensing dialog example

Option Explicit

Public MessageType As Integer

Private Sub Command1_Click()
   Unload Me
End Sub

Private Sub Form_Load()
   Select Case MessageType
      Case 0
         lblMessage.Caption = "This is a demo version of the gtpLicensed_
         component"
      Case 1
         lblMessage.Caption = "This component is unlicensed."
   End Select
End Sub

The MessageType public variable allows the calling module to specify which warning message to display: the standard splash screen identifying the component or a licensing warning. There is one thing you should keep in mind if you choose to display a splash screen. If you create an object from the DLL and then release it, after a while the DLL will unload. When you reload it, the splash screen will appear again.

There are only three differences between the gtpLicDT and gtpLicRT projects:

Why use conditional compilation to differentiate between the components instead of just a global constant? Because:

If you look in the frmLicTest.frm form in the LicTest project you'll see the following code:

' Changing reference is easy
Dim obj As New gtpLicensed

Private Sub Command1_Click()
   obj.A
End Sub

Let's say the project is initially created using the demo component gtpLicDT. How can you switch over to the other component? Easy. Just change the reference in the Project-References dialog box to reference the gtpLicRT project instead of the gtpLicDT project. No other code changes are necessary.

File-Based Control Licensing

A slight variation on this approach can be seen in the ctlTest.vbg program group, which contains LicCtl.vbp project and a test project, ctltest.vbp. The control uses the same Licenser module that you saw in the previous example, but in this case it defines the DLLCHECK conditional compilation variable.

The VerifyLicense procedure can be called at two possible times: during the control's initialization or during the InitProperties and ReadProperties events. If you choose the latter, be sure to perform the license test during both InitProperties and ReadProperties, to cover the creation of new controls and the loading of existing projects.

Option Explicit

Private Sub UserControl_Initialize()
   If Not VerifyLicense Then
      MsgBox "Licensing error"
      Err.Raise vbObjectError + 1000, "Control", "Control is not licensed for this platform"
   End If
End Sub

Private Sub UserControl_InitProperties()
   ' An alternate approach
   'If (Not Ambient.UserMode) And (Not VerifyLicense) Then
   '   MsgBox "Licensing error"
   '   Err.Raise vbObjectError + 1000, "Control", "Control is not licensed for_
   this platform"
   'End If
End Sub

You would perform the verification during initialization only if you do not care whether the control is in design time or runtime. For example: you might use this approach to enable or disable operation of the control for use with Office applications. If you do want to base verification on the container's UserMode, you must wait until the InitProperties or ReadProperties event, when the Ambient object exists. With ActiveX documents you might wait until the Show event, when you can also base the operation on the container, which is accessible through the Parent property.

The verification itself can be based on any criteria you wish. One common approach is to distribute a separate DLL or ActiveX DLL that contains design-time licensing information. You can test for the existence of version information in this DLL at the times you choose.

   #If DLLCHECK Then
      If IsVBEnvironment Then
         ' Check for DLL or object here.
         ' If not found, Set VerifyLicense to False
      Else
         VerifiedOnce = True
      End If
      VerifyLicense = VerifiedOnce
      Exit Function
   #End If

When licensing fails, you have a number of choices. The Visual Basic documentation correctly warns you against raising errors at times when the container does not expect it, such as during InitProperties, ReadProperties, and component Initialization. Why do I break this rule here? Because I assume that an attempt to run an unlicensed component is a fatal error. I want the container to abort if possible. But raising an error does not guarantee the control will fail to load (though it does have that effect in the containers I've tested this with). Thus, you should keep track of the fact that licensing failed in a module-level variable and use that variable to disable various parts of the control's operation if licensing fails.

As before, the control does bring up a message box to inform the end user that the problem is due to licensing. A better approach is to include a modal dialog box with information on how to obtain a license.

These two simple examples illustrate some important principles for licensing. Consider first the information that you have available:

Now consider the tools you have available to indicate that a control is licensed:

Combine the two and you see there are almost unlimited variations available for controlling the licensing of any type of ActiveX component.

For example: a limited duration component could be implemented as follows:

Sure, the user could figure out which registry entry you used or find the hidden file and restart the trial period. They can also set back the clock on their system. Remember that the intent here is to warn the user, because all of these approaches are based on the assumption that most developers are honest.

Closing Note

This brings us to the end of the first edition of Developing ActiveX Components with Visual Basic 5.0: A Guide to the Perplexed. While I suppose we can take it for granted there will be a Visual Basic 6.0 someday, whether there will be a second edition of this book depends largely on how well I've done my job here-how much this book helps you in your work.

I leave you with this last request. Visual Basic has grown from a small and easy programming environment to a large, complex environment that, while not easy, is still easier to use than anything else out there. I am sure there are some areas that could use additional explanation or commentary beyond what I was able to include here. In order to decide which subjects should be covered in future editions, I would like your input. What subjects do you still find confusing? Which areas need additional clarification or examples? Drop me a line at [email protected]. I can't promise to answer every message (I get a lot of e-mail), but I will keep your comments and consider them carefully.

Remember, too, to check www.desaware.com for corrections. No book is perfect. While I don't know of any errors as it goes to press, I'm sure a few have crept in somewhere.

Even though the main title of this book is Developing ActiveX Components with Visual Basic 5.0, I've tended to refer to it by its subtitle, A Guide to the Perplexed. This is how I've thought about it during the process of writing the book. So, if you find yourself reaching this point just a little bit less perplexed than you were when you started out, then I'll count this book a success.

Daniel Appleman
March 1997