|
|
Title | Register a product for a particular system |
Keywords | product, register, serial number, disk, system, shareware |
Categories | Windows, Software Engineering, Tips and Tricks |
|
|
Here's the idea.
- When the user first runs your program, it displays a message giving the user a product code tied to the user's system.
- The user calls customer support or something (sends email, logs on to a Web server, etc.) and gives this code.
- The customer support representative records the fact that this product serial number has registered (so the user cannot register it again on another computer) and possibly taking registration information such as customer name and email address.
- The customer support representative gives the user an activation code.
- The user enters the activation code in the program.
- The program saves the activation code in the registry so it can find it the next time it runs.
- The program verifies that the activation code is valid and then runs.
This example contains two programs: Product and RegistrationAssistant, a program that lets the customer service representative generate the correct activation code.
When Product runs, it calls function IsRegistered to see if the product is correctly registered. If it is not, the program displays the frmRegistration form which displays the product code to the user and provides instructions for getting an activation code.
Function IsRegistered uses the GetCombinedSerialNumber function to get the product's serial number combined with the system's hard disk serial number (to prevent the product from running if the user installs it on another system). It then fetches the registration code and registration result from the registry. It verifies that these values match a required format (20 digit strings in this example). It then uses some encryption function to encrypt the product code using the registration code. If the result matches the registration result, the product is registered.
|
|
Private Sub Form_Load()
' See if the program is registered.
Do While Not IsRegistered()
' Not registered.
' Let the user try to register.
frmRegistration.Show vbModal
If ExitApp Then
' The user canceled. Exit.
Unload Me
Exit Sub
End If
Loop
' Do whatever to get the program ready.
End Sub
' Return True if the program is registered.
Private Function IsRegistered() As Boolean
Dim combined_serial As String
Dim reg_code As String
Dim reg_result As String
' Get the combined product and
' disk serial number.
combined_serial = GetCombinedSerialNumber()
' See if the product is registered.
On Error Resume Next
reg_code = GetSetting(g_APPNAME, "Options", "RegCode", _
"")
reg_result = GetSetting(g_APPNAME, "Options", _
"RegResult", "")
On Error GoTo 0
If Not (reg_code Like _
"[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]" & _
"[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]") _
Or _
Not (reg_result Like _
"[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]" & _
"[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]") _
Then
IsRegistered = False
Exit Function
End If
' Combine the serial number and the RegCode
' in some manner. For example, use RegCode
' as the key to encrypt the serial number.
' Then see if this matches RegResult.
IsRegistered = ( _
Encrypt(combined_serial, reg_code) = reg_result)
End Function
|
|
Function GetCombinedSerialNumber gets the product serial number (from a constant) plus the disk's serial number returned by function GetDiskSerialNumber. GetDiskSerialNumber uses the GetVolumeInformation API function to get the disk's serial number.
|
|
' Return a combined product and disk serial number
' of the form 11111111112222222222.
Public Function GetCombinedSerialNumber() As String
GetCombinedSerialNumber = _
Format$(m_PRODUCT_SERIAL, "0000000000") & _
Format$(GetDiskSerialNumber(), "0000000000")
End Function
' Return the disk's serial number
' as a 10-digit string.
Private Function GetDiskSerialNumber() As String
Static serial_number As Long
Dim volume_name As String
Dim max_component_length As Long
Dim file_system_flags As Long
Dim file_system_name As String
If serial_number = 0 Then
' Get the disk serial number.
volume_name = Space$(1024)
file_system_name = Space$(1024)
If GetVolumeInformation(vbNullString, _
volume_name, Len(volume_name), _
serial_number, _
max_component_length, file_system_flags, _
file_system_name, Len(file_system_name)) = 0 _
Then
MsgBox "Error getting system information."
GetDiskSerialNumber = 0
Exit Function
End If
End If
GetDiskSerialNumber = Format$(serial_number, _
"0000000000")
End Function
|
|
|
|
|
|
The RegistrationAssistant program prompts the customer service representative for a product code. When the representatuiv presses Ok, the program uses the following code to generate the activation code. The code builds a random registration code. It then uses the same encryption routine used by Product to encrypt the product code using the random registration code. It displays the combined registration code and the encrypted result.
|
|
Private Sub cmdOk_Click()
Dim i As Long
Dim combined_serial As String
Dim reg_code As String
Dim reg_result As String
txtActivationCode.Text = ""
' Get the serial number.
combined_serial = txtSerialNumber.Text
If Not (combined_serial Like "[0-9][0-9][0-9][0-9]" & _
"[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]" _
& _
"[0-9][0-9][0-9][0-9][0-9][0-9]") Then
MsgBox "Invalid serial number format"
Exit Sub
End If
' Generate a random RegCode.
Randomize
For i = 1 To 20
reg_code = reg_code & Format$(Int(Rnd * 10))
Next i
' Calculate the correct result.
txtActivationCode.Text = _
reg_code & Encrypt(combined_serial, reg_code)
End Sub
|
|
Notes:
- This example simply concatenates the product serial number and the disk serial number to get a product code. You can use obfusticators to mix these together so it's not obvious to the user what the numbers represent.
- This example uses values that are all digits. You can convert them into strings using letters and numbers, possibly differentiating between upper and lower case letters. That can give you shorter codes that are easier to type while also making it less obvious to the user what they are.
- You can also add dashes, commas, or other punctuation to the codes to make them easier to read. Validate the values to match your format. You may want to strip out the punctuation for easier processing.
- This example's encryption method is a joke. Use something more secure such as Microsoft's Crypto API.
- When you debug the code, be sure that any failure means the product is not registered. For example, if the registration code or result is missing, don't let an empty encryption fool the program into thinking the registration ha passed.
Updates
Alrik Lustig had a problem on his system because his disks's serial number is negative when viewed as a Long. That put a negative sign (-) in the serial number and the simple encryption scheme used here couldn't handle it.
To fix it, he made the GetDiskSerialNumber function return the absolute value of the serial number.
GetDiskSerialNumber = Format$(Abs(serial_number), "0000000000")
A more sophisticated encryption scheme should handle negative serial numbers correctly. In fact, you might want to treat the serial number as a Hex value (which is probably the manufacturer's intent anyway).
Please let me know if you find any other bugs in this code.
|
|
|
|
|
|
|