Registration Tool
Volume Number: 12
Issue Number: 12
Column Tag: Shareware Tools
Registration Tools 
Tools for Providing Convenient Registration for Shareware
by James George, Los Alamos, NM
Note: Source code files accompanying article are located on MacTech CD-ROM orsource code disks.
As we put the finishing touches on our shareware masterpieces, we realized that
we had forgotten a vital link - a convenient registration method to encourage users to
register and pay for the shareware. We looked around and found none, but MacTech
saved the day with a timely article suggesting what was needed (Bill Midesitt - “How
to Make $1,000 Per Week Stuffing (Virtual) Envelopes, July 1995). We’ve
implemented many of the suggestions for the Metrowerks environment in Pascal or C.
We wanted an easy to include module which a) kept asking the user to register,
b) provided an easy way for a user to register, c) allowed the author to create
registration numbers, and d) allowed any user to un-register a registered copy to be
distributed freely. Thus, Register includes the headers, functions, and resources
providing the entire user interface and prints the registration form for mailing or
faxing.
Include Register in your Metrowerks project by adding Register.c and
Register.rsrc to your project , and inserting two lines in your setup/main module.
Listing 1: Typical Mac Template
Typical Mac Template
Include the Register headers, and check the registration.
#include “Register.h”
main()
{
(*call usual Macintosh initialization setup routines *)
CheckRegistration();
(* do your event loop *)
}
The User Interface
As your application starts, CheckRegistration retrieves the registered name and
registration number from the resources, recomputes the registration number from
the name and compares it to the registration number from the resource. If these
match, CheckRegistration returns and your application continues normally. When they
do not match, a information dialog encourages the user to register.
Figure 1. The Information Dialog
Naturally, only the item numbers for the “Register” and “Not Yet” button are
important, the rest of the dialog can be modified to promote your application.
If the user chooses “Not Yet”, the application continues normally; but, if
“Register” is selected, than the registration dialog allows the information to be
entered
Figure 2. The Registration Dialog
The user enters everything but the Registration Number, clicks “Print”, and
sends the printed form and fee to YOU! If the user clicks “Cancel” no information is
remembered; if the user click “OK”, everything is remembered except the credit card
information.
When you receive the registration, you fire up your master copy, enter some
special command and the MakeRegistration dialog allows you to enter the information,
create a valid registration number from the users name (click on “Make
Registration”), and print the information to return to the user.
Figure 3. The Make Registration Dialog
The Details
Now let’s look at the code in detail.
Listing 2: Register.h
Register.h
#define lockedAlert 400 /* application locked alert */
#define shareSplashAlert 401 /* the info screen */
#define registerDLog 314 /*the register dialog */
#define regPrintItem 3
#define regMkPwdItem 4
#define regFrstPrtItem 5
#define regLastPrtItem 19
#define regFrstOtherSaveItem 12
#define regLastOtherSaveItem 13
#define regNameItem 11
#define regNumberItem 19
#define regDataResType ‘ABCD’
#define regNumSeedValue 1234 /* seed value for test */
typedef long *longptr, **longhan;
/* Prototypes */
void PrintRegForm(DialogPtr theDialog);
long ComputeRegistration(Str255 name);
void MakeRegistration(void);
void UnRegister(void);
void Register(void);
void CheckRegistration(void);
lockedAlert is the id for the alert which informs the user that the application is
locked and thus no registration information can be remembered. The “OK” button must
remain item 1.
shareSplashAlert is the id for the information alert which describes the features
of the shareware and encourages the user to register. The item numbers for
“Register” and “Not Yet” item numbers must remain unchanged, but the rest of the
dialog may be modified.
registerDLog is the id for the registration (and make registration) dialog. The
“OK” and “Cancel” item numbers must remain unchanged, but the rest can be moved
as long as the appropriate defines are changed. regPrintItem is the “Print” button and
regMkPwdItem is the “Make Registration” button. The items from regFrstPritItem
thru regLastPrtItem are printed when the “Print” button is selected. The
regNameItem, the regNumberItem and the items from regFrstOtherSaveItem thru
regLastOtherSaveItem are saved in the resource file in the resource type
regDataResType.
regNumSeedValue is used by the ComputeRegistration routine as the seeded initial
value.
longptr and longhan are two data types used, and the prototypes are the actual
routines.
Now, lets look at all of the routines which comprise the registration module; they
are in Register.c
The registration number is calculated from the name by ComputeRegistration.
Listing 3: ComputeRegistration
ComputeRegistration
long ComputeRegistration(Str255 name)
if (StrLength(name) == 0) regnum = -1;
else regnum = regNumSeedValue;
for (i = 1; i<= StrLength(name); i++)
regnum = regnum + name[i];
return (regnum);
}
This computes a registration number for a name, by starting with a seed value,
and adding the character code for each character of the name, in order. Although not
unique, this allows for many variations by shareware authors. Some of the variations
are to change the seed, different arithmetic on individual characters (twice the value,
three times the value, alternately add and subtract...). Even these simple techniques
can be quite hard to break for the average user, but only a brain teaser for the
dedicated hacker.
After an application has started and initializes the Macintosh required managers,
it only needs to call CheckRegistration to implement most of the registration
functionality; the enhancements will be discussed later.
Listing 4: CheckRegistration
CheckRegistration
// CheckRegistration verifies the remembered name and registration number and asks // the user to
register the software if the verification fails.
void CheckRegistration(void)
StringHandle namehan;
longhan regwdhan;
long inregwdnum, computeregwdnum;
namehan =
(StringHandle) GetResource(regDataResType, regNameItem);
regwdhan =
(longhan) GetResource(regDataResType, regNumberItem);
if ( (namehan != nil) && (regwdhan != nil) )
(GetHandleSize((Handle) namehan) > 1) &&
(GetHandleSize((Handle) regwdhan) == 4) )
HLock( (Handle) namehan);
HLock( (Handle) regwdhan);
computeregwdnum = ComputeRegistration(*namehan);
inregwdnum = **regwdhan;
HUnlock( (Handle) namehan);
HUnlock( (Handle) regwdhan);
if ( namehan != nil) ReleaseResource( (Handle) namehan);
if ( regwdhan != nil) ReleaseResource( (Handle) regwdhan);
regwdhan = nil;
namehan = nil;
if ( inregwdnum != computeregwdnum) Register();
}
} else
if ( namehan != nil ) ReleaseResource( (Handle) namehan);
if ( regwdhan != nil ) ReleaseResource( (Handle) regwdhan);
Register();
}
}
CheckRegistration gets the remembered name and registration number from the
regDataResType resource. If either is not there, then Register is called, otherwise a
registration number is calculated from the remembered name and compared to the
remembered registration number, and if they differ, then Register is called.
Listing 5: Register
Register
void Register(void)
DialogPtr theDialog;
Handle theTextHdl;
Rect itemBox;
short itemHit, theType, index;
GrafPtr thePort;
Str255 namestr, regstr;
long regwordL;
StringHandle nameHan, strHan;
longhan regsHan;
FlushEvents (everyEvent, 0); /*throws out leftover events */
if ( Alert(shareSplashAlert, nil) == OK )
FlushEvents (everyEvent, 0);
theDialog =
GetNewDialog (registerDLog, nil, (WindowPtr) -1);
if (theDialog != nil)
Â/*Hide the Make Reg Number button*/
HideDialogItem(theDialog,regMkPwdItem);
/*fill in text fields from save values*/
strHan =
(StringHandle) GetResource(regDataResType, regNameItem);
if ( strHan != nil)
GetDialogItem (theDialog, regNameItem, &theType,
&theTextHdl, &itemBox);
SetDialogItemText (theTextHdl, *strHan);
ReleaseResource((Handle) strHan);
}
for ( index = regFrstOtherSaveItem;
index <= regLastOtherSaveItem; index ++)
strHan = (StringHandle) GetResource(regDataResType, index);
if (strHan != nil)
GetDialogItem (theDialog, index, &theType,
&theTextHdl, &itemBox);
SetDialogItemText (theTextHdl, *strHan);
ReleaseResource((Handle) strHan);
}
}
GetPort(&thePort);
SetPort (theDialog);
ShowWindow (theDialog);
do
ModalDialog (nil, &itemHit);
if ( itemHit == regPrintItem ) PrintRegForm(theDialog);
}while (itemHit > cancel);
if ( (itemHit == ok) || (itemHit == regPrintItem) )
GetDialogItem (theDialog, regNameItem, &theType,
&theTextHdl, &itemBox);
GetDialogItemText (theTextHdl, namestr);
GetDialogItem (theDialog, regNumberItem, &theType,
&theTextHdl, &itemBox);
GetDialogItemText (theTextHdl,regstr);
StringToNum(regstr, ®wordL);
if ( Length(namestr) > 0)
regsHan = (longhan) NewHandle(4);
nameHan = NewString(namestr);
**regsHan = regwordL;
AddResource( (Handle) nameHan, regDataResType,
regNameItem , “\p”);
if ( ResError() != noErr)
{ itemHit =
StopAlert(lockedAlert,nil);}
WriteResource( (Handle) nameHan);
AddResource( (Handle) regsHan,regDataResType,
regNumberItem , “\p”);
if ( ResError() != noErr)