home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C!T ROM 2
/
ctrom_ii_b.zip
/
ctrom_ii_b
/
PROGRAM
/
PASCAL
/
RKPLUS33
/
RKPLUS.DOC
< prev
next >
Wrap
Text File
|
1993-10-19
|
54KB
|
1,468 lines
R k P l u s ( t m ) v e r s i o n 3 . 3
Turbo Pascal (tm) Registration Key Unit
by C. Scott Davis
Copyright (c) 1991-93 Serious Cybernetics
6804 Belton Place * Lula, GA * 30554-2622 * USA
RkPlus(tm) 3.3 Registration key Unit
T A B L E O F C O N T E N T S
===================================================================
D e s c r i p t i o n Sec
What Is RkPlus(tm)? ................................ 1.0
Getting Started With RkPlus(tm) .................... 2.0
Five Methods Of Using RkPlus(tm) ................... 3.0
RkPlus(tm) Type Definitions ........................ 4.0
RkPlus(tm) Constants ............................... 5.0
RkPlus(tm) Variables ............................... 6.0
RkPlus(tm) Functions And Procedures ................ 7.0
Detailed Type Information .......................... 8.0
RkpRec ............................................. 8.1
EncFuncType ........................................ 8.2
FileFuncType ....................................... 8.3
Detailed Constant Information ...................... 9.0
NoError ............................................ 9.1
FileNotFound ....................................... 9.2
PathNotFound ....................................... 9.3
TooManyFiles ....................................... 9.4
AccessDenied ....................................... 9.5
InvalidFile ........................................ 9.6
InvalidRecord / RecordNotFound ..................... 9.7
InvalidParameter ................................... 9.8
VersionMismatch .................................... 9.9
NoEncodeFunc ....................................... 9.10
InvalidKey ......................................... 9.11
ExpiredKey ......................................... 9.12
BadTPU ............................................. 9.13
Detailed Variable Information ...................... 10.0
BaseYear ........................................... 10.1
UseExpDays ......................................... 10.2
UseExePath ......................................... 10.3
KeyFileSize ........................................ 10.4
Rkp.Registered ..................................... 10.5
Rkp.ID ............................................. 10.6
Rkp.Name1 .......................................... 10.7
Rkp.Name2 .......................................... 10.8
Rkp.Name3 .......................................... 10.9
Rkp.Message ........................................ 10.10
Rkp.Level .......................................... 10.11
Rkp.ExpYear / Rkp.ExpMonth / Rkp.Day ............... 10.12
Rkp.Key ............................................ 10.13
KeyFileCode ........................................ 10.14
Detailed Procedure And Function Information ........ 11.0
RkPlusVer .......................................... 11.1
BadSystemDate ...................................... 11.2
RkpOK .............................................. 11.3
RkpError ........................................... 11.4
SetEncode .......................................... 11.5
SetKeyFile ......................................... 11.6
KeyFileName ........................................ 11.7
ExeFileName ........................................ 11.8
GetKeyFileSize ..................................... 11.9
MakeKey ............................................ 11.10
ValidKey ........................................... 11.11
SetRegInfo ......................................... 11.12
CreateKey .......................................... 11.13
VerifyKey .......................................... 11.14
GetRegInfo ......................................... 11.15
SaveRegInfo ........................................ 11.16
BrandRegInfo ....................................... 11.17
SetFileEnc ......................................... 11.18
Additional Information On RkPlus(tm) ............... 12.0
RkPlus(tm) Source Code Availability ................ 13.0
What's Next For RkPlus(tm)? ........................ 14.0
ShareWare Notice And Registration .................. 15.0
RkPlus(tm) Support ................................. 16.0
Credits ............................................ 17.0
Turbo Pascal (tm) Units from Serious Cybernetics ... 18.0
Other Recommended Turbo Pascal (tm) Units .......... 19.0
Copyright Notices .................................. 20.0
1.0 - What is RkPlus(tm)?
RkPlus(tm) is an enhanced version of our original rKey Registration Key
Unit. It is a Turbo Pascal (tm) Unit designed to allow programmers to
easily handle secure registration keys in their software. All of the key
encryption, checking, and key file routines are handled in RkPlus(tm),
requiring little effort on the part of the programmer. RkPlus(tm) can allow
anything from simple registration messages to multiple registration levels,
limited use demo keys, and custom written encoding functions.
There are seven versions of RkPlus included within the main RKPLUS33
distribution archive, each in it's own unique archive :
RKP50TPU - RkPlus(tm) for Turbo Pascal (tm) 5.0
Contains RKPLUS.TPU, RKP2ENC.TPU and RKP3ENC.TPU
RKP55TPU - RkPlus(tm) for Turbo Pascal (tm) 5.5
Contains RKPLUS.TPU, RKP2ENC.TPU and RKP3ENC.TPU
RKP60TPU - RkPlus(tm) for Turbo Pascal (tm) 6.0
Contains RKPLUS.TPU, RKP2ENC.TPU and RKP3ENC.TPU
RKP10TPU - RkPlus(tm) for Turbo Pascal (tm) 1.0 for Windows (tm)
Contains RKPLUS.TPU, WDCOMPAT.TPU, RKP2ENC.TPU and RKP3ENC.TPU
RKP15TPU - RkPlus(tm) for Turbo Pascal (tm) 1.5 for Windows (tm)
Contains RKPLUS.TPU, WDCOMPAT.TPU, RKP2ENC.TPU and RKP3ENC.TPU
RKP70TPU - RkPlus(tm) for Borland/Turbo Pascal (tm) 7.0
Contains RKPLUS.TPU, RKP2ENC.TPU, RKP3ENC.TPU,
RKPLUS.TPP, RKP2ENC.TPP, RKP3ENC.TPP,
RKPLUS.TPW, WDCOMPAT.TPW, RKP2ENC.TPW and RKP3ENC.TPW
RKPSBP - RkPlus(tm) for Stony Brook Pascal+(tm)
Contains RKPLUS.SBL, RKPLUS.LIB, RKP2ENC.LIB, RKP3ENC.LIB,
RKPLUS.INT, RKP2ENC.INT, and RKP3ENC.INT.
Note: If you use a specific version of Turbo Pascal (tm), be sure to
extract the RkPlus(tm) files from the proper internal archive! Using the
wrong version of RkPlus(tm) is sure to cause problems. For instance, if you
program using Turbo Pascal (tm) version 6.0, be sure you are using the
RkPlus(tm) files from the RKP60TPU archive!
Within this documentation are many examples and Turbo Pascal (tm) code
segments. These segments are necessarily brief, but should be sufficient to
explain the various functions of RkPlus(tm). Due to restrictions necessary
when distributing and modifying a text document of this nature, all
pagination has been removed from this document. A complete professionally
printed and bound manual is available for RkPlus(tm) for a nominal fee (see
section 15.0 on registration).
2.0 - Getting Started with RkPlus(tm)
There are basically 3 approaches to using RkPlus(tm) :
1) If you have an existing programme written using RkPlus(tm) version 2.x
(2.0 to 2.4), and you want to maintain compatibility with your existing
keys, you can simply use the Rkp2Enc unit. This unit contains RkPlus(tm)
version 2.x/compatible encoding routines and automatically interfaces itself
with RkPlus(tm). Examples of this approach are contained in the RKPDEMO2
archive.
2) If you don't want to write your own encoding functions (but don't
require RkPlus(tm) 2.x compatibility), you can simply use the Rkp3Enc unit.
This unit contains new RkPlus(tm) version 3.x encoding routines and
automatically interfaces itself with RkPlus(tm). Examples of this approach
are contained in the RKPDEMO3 archive.
3) If you want to be totally assured of the uniqueness and security of your
keys, you can write your own encoding functions and specify them with the
SetEncode procedure (see "SetEncode" in section 11.5). This is somewhat
more involved that the first approach, but gives you more control of key
generation. Examples of this approach are contained in the RKPDEMO archive.
3.0 - Five Methods of Using RkPlus(tm)
The various sample programmes demonstrate 5 methods of handling keys :
1) Distribute your programme (see SAMPLE1.PAS) and use a key file
generation programme (see GENFILE.PAS), which you do NOT distribute, to
create a key file for each user who registers. You then send the user the
key file.
2) Distribute your programme (see SAMPLE1.PAS) and a registration programme
(see REGISTER.PAS). You then use a key generation programme (see
GENKEY.PAS), which you do NOT distribute, to create a key number for each
user who registers. You then send the user the key number, which he/she
enters into the registration programme to create a key file.
3) Distribute your programme (see SAMPLE2.PAS), which has it's own
registration routine. You then use a key generation programme (see
GENKEY.PAS), which you do NOT distribute, to create a a key number for each
user who registers. You then send the user the key number, which he/she
enters into the programme to create a key file.
4) Distribute your programme (see SAMPLE3.PAS), which has its own
configuration file. You then use a key generation programme (see
GENKEY.PAS), which you do NOT distribute, to create a a key number for each
user who registers. You then send the user the key number, which he/she
enters into the configuration file. There is no key file required with this
method.
5) Distribute your programme (see SAMPLE4.PAS) and a branding programme
(see BRAND.PAS). You then use a key generation programme (see GENKEY.PAS),
which you do NOT distribute, to create a key number for each user who
registers. You then send the user the key number, which he/she enters into
the branding programme to write the registration information directly into
the EXE file.
4.0 - RkPlus(tm) Type Definitions
The following Types are defined in RkPlus(tm). See section 8 for details on
each.
RkpRec
EncFuncType
FileFuncType
5.0 - RkPlus(tm) Constants
The following Constants are defined in RkPlus(tm). See section 9 for
details on each.
NoError
FileNotFound
PathNotFound
TooManyFiles
AccessDenied
InvalidFile
InvalidRecord
RecordNotFound
InvalidParameter
VersionMismatch
NoEncodeFunc
InvalidKey
ExpiredKey
BadTPU
6.0 - RkPlus(tm) Variables
The following Variables are defined in RkPlus(tm). See section 10 for
details on each.
BaseYear
UseExpDays
UseExePath
KeyFileSize
Rkp
KeyFileCode
7.0 - RkPlus(tm) Procedures and Functions
The following Procedures and Functions are defined in RkPlus(tm). See
section 11 for details on each.
Functions:
RkPlusVer
BadSystemDate
RkpOK
RkpError
KeyFileName
ExeFileName
GetKeyFileSize
MakeKey
ValidKey
Procedures:
SetEncode
SetKeyFile
SetRegInfo
CreateKey
VerifyKey
GetRegInfo
SaveRegInfo
BrandRegInfo
SetFileEnc
8.0 - Detailed Type Information
This section contains detailed information on all Types defined in
RkPlus(tm).
8.1 - RkpRec
RkpRec = Record
Registered : Boolean;
ID : String[36];
Name1 : String[36];
Name2 : String[36];
Name3 : String[36];
Message : String[36];
Level : Byte;
ExpYear : Word;
ExpMonth : Byte;
ExpDay : Byte;
Key : String[12];
End;
RkpRec is the Type used by the variable Rkp, which contains the registration
information (see "Detailed Variable Information" in section 10).
8.2 - EncFuncType
EncFuncType = Function(t1,t2,t3 : String; l : Byte; i : Integer) : Word;
EncFuncType is the function type used to define a custom encoding function
(see "SetEncode" in section 11.5).
8.3 - FileFuncType
FileFuncType = Function(v : Byte; b : Boolean) : Byte;
This type defines the function type that would be passed to SetFileEnc, when
specifying a File Encoding Function (see SetFileEnc). It is automatically
set by Rkp2Enc and Rkp3Enc. You will only need to use FileFuncType if you
are using user-written encoding functions.
9.0 - Detailed Constant Information
This section contains detailed information on all Constants interfaced by
RkPlus(tm). The constants defined by RkPlus(tm) are used to define values
that may be returned by RkpError (Section 11.4). In addition to those
defined as constants, error codes $0001 to $00FF correspond to the values
returned by the Turbo Pascal (tm) IoResult function.
9.1 - NoError
NoError = $0000;
If RkpError returns NoError then no error has occurred. If this is the
case, then RkpOK will also return True. If RkpError returns any non-zero
value, then RkpOK will return False.
9.2 - FileNotFound
FileNotFound = $0002;
If RkpError returns FileNotFound then the previous function or procedure was
unable to find a required file.
9.3 - PathNotFound
PathNotFound = $0003;
If RkpError returns PathNotFound then the previous function or procedure was
unable to find the path of a required file.
9.4 - TooManyFiles
TooManyFiles = $0004;
If RkpError returns TooManyFiles then RkPlus(tm) was unable to open a file
because not enough file handles were defined in CONFIG.SYS.
9.5 - AccessDenied
AccessDenied = $0005;
If RkpError returns AccessDenied then an attempt was made to write to a Read
Only file or a currently open shared file.
9.6 - InvalidFile
InvalidFile = $0101;
If RkpError returns InvalidFile then the previous function or procedure
attempted to process a file that is not a valid RkPlus(tm) file.
9.7 - InvalidRecord / RecordNotFound
InvalidRecord = $0102;
RecordNotFound = $0103;
These errors are not returned by RkpError, but are included for future use
and compatibility with other Serious Cybernetics units.
9.8 - InvalidParameter
InvalidParameter = $0201;
If RkpError returns InvalidParameter, then the previous function or
procedure was passed invalid data.
9.9 - VersionMismatch
VersionMismatch = $0202;
This error is not currently used by RkPlus(tm), but is included for future
use and is presently used by the encoding units (Rkp2Enc and Rkp3Enc).
9.10 - NoEncodeFunc
NoEncodeFunc = $0301;
If RkpError returns NoEncodeFunc then you are attempting to use RkPlus(tm)
without either providing a custom encode function or using one of the
encoding units (Rkp2Enc or Rkp3Enc), both of which automatically set their
encode functions.
9.11 - InvalidKey
InvalidKey = $0302;
If RkpError returns InvalidKey then the current key in the Rkp record
(Rkp.Key) is not valid.
9.12 - ExpiredKey
ExpiredKey = $0303;
If RkpError returns ExpiredKey then the current key in the Rkp record
(Rkp.Key) has expired.
9.13 - BadTPU
BadTPU = $FFFF;
If RkpError returns BadTPU then the RKPLUS.TPU file is corrupt or has been
tampered with and SHOULD BE REPLACED IMMEDIATELY.
10.0 - Detailed Variable Information
This section contains detailed information on all Variables interfaced by
RkPlus(tm).
10.1 - BaseYear
BaseYear : Word;
This variable contains the base year that will be used when calculating
expiration keys. It is initialised to 1992 by RkPlus(tm). It is VERY
important that the value of BaseYear be the same in the programme that
generated the key and the programme that uses it, otherwise expiration dates
will be calculated incorrectly.
Example :
BaseYear := 1990;
All expiration dates will be calculated and stored as offsets from
1-Jan-1990.
10.2 - UseExpDays
UseExpDays : Boolean;
This variable determines whether expiration days will be included in
expiration dates for keys. If UseExpDays is True (default), then expiration
days will be included (allowing a valid range of 21 years). If UseExpDays
is False, then expiration days will not be included (allowing a valid range
of 304 years). If expiration days are not used, keys will expire on the
first day of the expiration month. The Rkp2Enc unit sets UseExpDays to
False to maintain compatibility with RkPlus(tm) version 2.x keys.
10.3 - UseExePath
UseExePath : Boolean;
This variable controls how RkPlus(tm) handles filenames with no specified
path. If UseExePath is True (default), then RkPlus(tm) will use the path
that the programme was executed from if no path is specified. If UseExePath
is False, then RkPlus(tm) will use the current path if no path is specified.
10.4 - KeyFileSize
KeyFileSize : Integer;
This variable is used by SaveRegInfo to determine the size of the key file
when it is created. If KeyFileSize is less than or equal to 337 (the number
of bytes used by RkPlus(tm)), the file will be 337 bytes long. However, if
KeyFileSize is greater than 337, random bytes will be appended to the key
file to cause it to be KeyFileSize bytes long.
Example :
KeyFileSize := 1024;
Randomize;
Any future calls to SaveRegInfo will result in a key file that has been
padded to 1024 bytes.
Note: RkPlus(tm) does NOT automatically randomize the seed number used to
generate the random bytes that are appended to the key file. In order to
have true random values, your programme must call the Randomize procedure
before SaveRegInfo is called. If you are not using KeyFileSize (it is less
than or equal to 337), then you do not need to call Randomize (since no
random bytes will be appended).
10.5 - Rkp.Registered
Rkp.Registered : Boolean;
This field of the Rkp record is initialised by RkPlus(tm) to False. It is
set by CreateKey, VerifyKey, GetRegInfo, SaveRegInfo, and BrandRegInfo to
True if the current key contained in Rkp.Key is valid and has not expired.
Example :
If Rkp.Registered then
The code following would only be executed if the programme has been
registered. This assumes, of course, that an RkPlus(tm) procedure (such as
GetRegInfo or VerifyKey) has been called previously.
10.6 - Rkp.ID
Rkp.ID : String[36];
This variable is initialised by RkPlus(tm) to ''. Rkp.ID is not used by
RkPlus(tm), and has no effect on key encryption. However, it is read from
the key file by GetRegInfo, written to the key file by SaveRegInfo, and
branded into the EXE file by BrandRegInfo. This will normally be used to ID
your key files, so that your programme can distinguish its own key files
from those of other programmes. However, since it is not used in the
encryption of the registration key, it can be used to store any information
that you want.
Example :
If (Rkp.ID <> 'RkData') then
WriteLn('Error! This is NOT an RkData key file!');
If Rkp.ID doesn't equal 'RkData' then the message 'Error! This is NOT an
RkData key file!' will be displayed.
10.7 - Rkp.Name1
Rkp.Name1 : String;
This variable is initialised by RkPlus(tm) to ''. It is used (along with
Rkp.Name2 and Rkp.Name3) in the encryption of the registration key by
CreateKey, VerifyKey, SaveRegInfo (which also writes it to the key file),
and BrandRegInfo (which also brands it to the EXE file). It is read from
the key file by GetRegInfo. This will normally contain the name of the
person that the software is registered to.
Example :
If Rkp.Registered then
WriteLn('Registered to ',Rkp.Name1)
Else
WriteLn('Unregistered')
If the programme is registered, it will display the name of the person it is
registered to. Otherwise, it will display "Unregistered".
10.8 - Rkp.Name2
Rkp.Name2 : String;
This variable is initialised by RkPlus(tm) to ''. It is used (along with
Rkp.Name1 and Rkp.Name3) in the encryption of the registration key by
CreateKey, VerifyKey, SaveRegInfo (which also writes it to the key file),
and BrandRegInfo (which also brands in to the EXE file). It is read from
the key file by GetRegInfo. This may contain a company name, a BBS name, or
any additional information that you want to use in key encryption.
Example :
If Rkp.Registered then Begin
WriteLn('Registered to ',Rkp.Name1,'.');
WriteLn('For use at ',Rkp.Name2,'.');
End Else
WriteLn('Remember to Register!');
If the programme is registered, it will display the name and company of the
user that it is registered to. Otherwise, it will display "Remember to
Register!".
10.9 - Rkp.Name3
Rkp.Name3 : String;
This variable is initialised by RkPlus(tm) to ''. It is used (along with
Rkp.Name1 and Rkp.Name2) in the encryption of the registration key by
CreateKey, VerifyKey, SaveRegInfo (which also writes it to the key file),
and BrandRegInfo (which also brands it into the EXE file). It is read from
the key file by GetRegInfo. This may contain a customer number, address, or
any additional information that you want to use in key encryption.
Example :
If Rkp.Registered then Begin
WriteLn('Registered to ',Rkp.Name1);
WriteLn(' ',Rkp.Name2);
WriteLn(' ',Rkp.Name3);
End Else
WriteLn('Unregistered')
If the programme is registered, it will display the name of the person it is
registered to followed by a 2 line address (from Rkp.Name2 and Rkp.Name3).
Otherwise, the message 'Unregistered' will be displayed.
10.10 - Rkp.Message
Rkp.Message : String[36];
This variable is initialised by RkPlus(tm) to ''. Rkp.Message is not used by
RkPlus(tm), and has no effect on key encryption. However, it is read from the
key file by GetRegInfo, written to the key file by SaveRegInfo, and branded to
the EXE file by BrandRegInfo. This will normally be used to ID your key
files, so that your programme can distinguish your key files from those of
other programers/companies. However, since it is not used in the encryption
of the registration key, it can be used to store any information that you
want.
Example :
If(Rkp.Message <> 'Serious Cybernetics') then
WriteLn('Error! This is NOT a Serious Cybernetics key file!');
If Rkp.Message doesn't equal 'Serious Cybernetics', then the message 'Error!
This is NOT a Serious Cybernetics key file!' will be displayed.
10.11 - Rkp.Level
Rkp.Level : BYTE;
This variable is initialised by RkPlus(tm) to 0. It is used in the
encryption of the registration key by CreateKey, VerifyKey, SaveRegInfo
(which also writes it to the key file), and BrandRegInfo (which also brands
it to the EXE file). It is read from the key file by GetRegInfo. If you
don't wish to use registration levels, Rkp.Level should always be 0.
Example :
If Rkp.Level > 0 then
WriteLn('[G]raphs');
If Rkp.Level > 1 then
WriteLn('[O]ther functions');
If the registration level is greater than 0 then the menu option "[G]raphs"
would be displayed. If the registration level is greater than 1 then the
menu option "[O]ther functions" would also be displayed.
Note : Unlike the expiration date, which is binary encoded into the key
number (after the encoding functions are called) and therefore can be
extracted from any given key number, the registration level is only used for
the encryption of the key, and is stored in the key file but can not be
extracted from a key number itself. Therefore, if you use registration
levels, you will need to make sure that the brand programme or key file
creation programme knows, or can determine, the registration level, because
it can NOT be extracted from the key number alone (see SAMPLE2.PAS,
REGISTER.PAS, and BRAND.PAS for examples).
10.12 - Rkp.ExpYear, Rkp.ExpMonth, Rkp.Day
Rkp.ExpYear : Word;
Rkp.ExpMonth : Byte;
Rkp.ExpDay : Byte;
These variables are initialised by RkPlus(tm) to 0. They are binary-encoded
into the registration key by CreateKey, SaveRegInfo, and BrandRegInfo. They
are decoded from the registration key by VerifyKey and GetRegInfo. Valid
values for Rkp.ExpYear are 0 (No expiration) or BaseYear+1 to BaseYear+340
(if UseExpDays is False) or BaseYear+1 to BaseYear+21 (if UseExpDays is
True) . Valid values for Rkp.ExpMonth are 0 (No expiration) or 1 to 12.
Valid values for Rkp.ExpDay are 0 (No expiration) or odd days 1 to 29 (if
UseExpDays is True). Even values (1 to 28) will be rounded up to the next
odd value. If you don't wish to use expiration dates, Rkp.ExpYear,
Rkp.ExpMonth, and Rkp.ExpDay should always be 0.
Example :
Const
Months : Array[1..12] of String[3] =
('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec');
BaseYear := 1990;
UseExpDays := False;
.
. { rest of programme would be here }
.
If (RkpError = ExpiredKey) then
WriteLn('Your key expired 1-',Months(Rkp.ExpMonth),'-',Rkp.ExpYear)
Else If Rkp.Registered then
WriteLn('Your key will expire 1-',Months(Rkp.ExpMonth),'-',Rkp.ExpYear);
If the key has expired, the date that the key expired is displayed.
Otherwise, if the programme is registered, the date that the key will expire
is displayed.
10.13 - Rkp.Key
Rkp.Key : String[12];
This variable is initialised by RkPlus(tm) to '000000000000'. It is set by
CreateKey and GetRegInfo. It is used by VerifyKey, SaveRegInfo, and
BrandRegInfo. This contains the 12 digit alphanumeric registration key as a
string.
Example :
If Rkp.Registered then Begin
WriteLn('Registered to ',Rkp.Name1,'.');
WriteLn('Registration key is ',Rkp.Key,'.');
End Else
WriteLn('Not registered.');
WriteLn('Please read the READ.ME file for more info.');
End;
If the programme is registered, the name of the person that it is registered
to, and the registration key will be displayed. Otherwise, a message will
be displayed telling the user how to register the programme.
10.14 - KeyFileCode
KeyFileCode : LongInt;
This variable defaults to 0 (no KeyFile scrambling). If it set to any valid
non-zero value ($00000001 to $FFFFFFFF) then it will be used to generate an
algorythm to "scramble" the key file as it is written. If KeyFileCode is
not set to the exact same value in programmes which read the key file, the
file will be unreadable.
KeyFileCode is designed to prevent hackers from being able to use a copy of
RkPlus(tm) to read your key files. It has the additional effect of making
the key file illegible when listed by text file viewers.
11.0 - Detailed Procedure And Function Information
The following procedure and functions are available when using the
RkPlus(tm) TPU:
11.1 - RkPlusVer
Function RkPlusVer : String;
RkPlusVer returns the current version of RkPlus(tm).
Example :
WriteLn('using ',RkPlusVer);
will display "using RkPlus 3.3".
11.2 - BadSystemDate
Function BadSystemDate : Boolean;
This Function will return True if the current system date is 1-Jan-1980
(which usually indicates that the date was not set on the PC), or False if
the current system date is anything other than 1-Jan-1980.
The main purpose for this Function is for use with limited keys (with
embedded expiration dates). By calling BadSystemDate, your programme can
handle situations where the system date was not set (which would cause
expiration dates to be meaningless).
Example :
If BadSystemDate then Begin
WriteLn('The system date must be set!');
Halt(1);
End;
If the system date was not set (BadSystemDate returns True) then display a
message and exit with an ErrorLevel of 1.
11.3 - RkpOK
Function RkpOK : Boolean;
RkpOK will return True if the result of the last procedure or function was
NoError. If RkpOK is False, then an error has occurred.
Example :
If RkpOK then
WriteLn('Key file written!');
If RkpOk returns True, then the message "Key file written!" will be
displayed.
11.4 - RkpError
Function RkpError : Word;
RkpError will return the actual error code of the last procedure/function.
If RkpError = NoError, then no error occurred. If RkpError is between $0001
and $00FF, then an I/O error occurred during the operation and the result is
an IoResult code. Otherwise, the error is an RkPlus(tm) error (see
"Detailed Constant Information").
Example :
If RkpOK then
WriteLn('Key file written.')
Else
WriteLn('Error ',RkpError,'!');
If no error occurred, "Key file written." will be displayed. Otherwise, the
error code will be displayed.
11.5 - SetEncode
Procedure SetEncode(e1, e2, e3 : EncFuncType);
This procedure will specify the functions that will be called to encode the
registration key. An encoding function must be defined as FAR {$F+} and
must be of the type EncFuncType. Each encode function is used to encode one
4-character section of the final key number (the actual number to character
conversion is handled by RkPlus(tm)) and is passed 3 strings, a Byte and an
Integer. Any or all of these values may be used by any single encode
function to produce a Word result. However, the 3 Strings and the Byte
should be used in at least one of the encode functions. Otherwise, that
value will have no effect on key generation. The 3 strings correspond to
Rkp.Name1, Rkp.Name2 and Rkp.Name3. The Byte corresponds to the registration
level (Rkp.Level) and the Integer is the expiration date stored as an offset
from 1-Jan of BaseYear. Since the expiration date will be binary-encoded
into the key number after the encode function returns, it is not required
that it be used in the encode function. If you use Rkp2Enc (for RkPlus(tm)
2.x/compatible keys) or Rkp3Enc (for RkPlus(tm) 3.x keys), you do not need
to provide encoding functions or call SetEncode (it is handled automatically
in the encoding unit's startup code).
11.6 - SetKeyFile
Procedure SetKeyFile(s : String);
This procedure will specify the name of the key file for RkPlus(tm) to use
(with optional path and extension). The key file will default to the name
of the programme with an extension of '.RKP' (or '.EXE' when using
BrandRegInfo) and the path will default to the path the programme was
executed from (if UseExePath is True) or the current directory (if
UseExePath is False).
Example :
UseExePath := False;
SetKeyFile('DEMO1');
RkPlus(tm) will use 'DEMO1.RKP' (in the current directory) as the key file.
If BrandRegInfo is called, it will use 'DEMO1.EXE' (in the current
directory).
11.7 - KeyFileName
Function KeyFileName : String;
This function will return the full path, filename and extension of the key
file.
Example :
UseExePath := True;
SetKeyFile('DEMO2');
WriteLn(KeyFileName);
If the current directory is (for example) D:\ and the programme was executed
from (for example) C:\DEMOS, then it would display "C:\DEMOS\DEMO2.RKP".
11.8 - ExeFileName
Function ExeFileName : String;
This function will return the full path, filename and extension of the exe
file that would be branded by BrandRegInfo. This will be identical to the
result of KeyFileName, except that the extension will be '.EXE'.
Example :
UseExePath := False;
SetKeyFile('DEMO3');
WriteLn(ExeFileName);
If the current directory is (for example) D:\ and the programme was executed
from (for example) C:\DEMOS, then it would display "D:\DEMO3.EXE".
11.9 - GetKeyFileSize
Function GetKeyFileSize : Integer;
This Function will return the size (in bytes) of the key file.
Example :
If (GetKeyFileSize <> 1024) then
WriteLn('Invalid file size');
If the size of the key file is not equal to 1024, then "Invalid File Size"
will be displayed.
11.10 - MakeKey
Function MakeKey(Name1,Name2,Name3 : String;
Level : Byte;
ExpYear : Word;
ExpMonth,ExpDay : Byte) : String;
The function MakeKey will return a string containing the 12 digit
registration key for Names and Level (using the encode functions defined
with SetEncode) specified, with an encoded expiration date of ExpYear,
ExpMonth and ExpDay. If you do not wish to use registration levels, simply
pass a 0 as the Level parameter. If you do not wish to use expiration
dates, simply pass 0 as the ExpYear, ExpMonth and ExpDay parameters. ExpDay
will only be used if UseExpDays is True. Unlike the higher-level CreateKey
procedure, this function does NOT use or change the values of the Rkp
record.
Example :
Write('Enter name : ');
ReadLn(n);
Write('Enter company : ');
ReadLn(c);
Write('Enter phone number (XXX) XXX-XXXX : ');
ReadLn(p);
k := MakeKey(n,c,p,0,0,0,0); { registration levels and expiration
dates are not being used }
WriteLn;
WriteLn('Registration key is ',k);
This will prompt for a name, company name and phone number. MakeKey is then
passed the name, company name and phone number, a 0 for the registration
level and 0 for expiration year, month and day. It will return the key in
the variable k, which is then displayed.
It is usually preferable to use the higher-level CreateKey procedure,
instead of MakeKey. MakeKey is included to allow for situations where you
may need to make a key and don't want to affect the values contained in the
Rkp record.
11.11 - ValidKey
Function ValidKey(Name1,Name2,Name3 : String;
Level : Byte;
Key : String) : Boolean;
ValidKey will return TRUE if the Key is valid for Name1, Name2, Name3 and
Level (using the encode functions defined with SetEncode). If you do not
wish to use registration levels (and levels weren't used when the key was
generated), simply pass 0 as the Level parameter. If ValidKey returns
False, the key is not valid. Unlike the higher-level procedure VerifyKey,
this function does NOT use or change the values of the Rkp record.
Example :
Write('Enter your name : ');
ReadLn(n);
Write('Enter your BBS name : ');
ReadLn(b);
Write('Enter your FidoNet address : ');
ReadLn(f);
Write('Enter your registration key : ');
ReadLn(k);
If Not ValidKey(n,b,f,0,k) then Begin { registration levels not used }
WriteLn('Invalid key!');
Halt(1);
End;
This programme will prompt the user to enter a name, BBS name, FidoNet
address and a registration key. If the registration key is not valid, the
programme will display 'Invalid key!' and Halt with an errorlevel of 1.
It is usually preferable to use the higher-level VerifyKey procedure,
instead of ValidKey. ValidKey is included to allow for situations where you
may need to validate a key and don't want to affect the values contained in
the Rkp record.
11.12 - SetRegInfo
Procedure SetRegInfo(t,s1,s2,s3,m : String;
l : Byte;
ey : Word;
em,ed : Byte;
k : String);
SetRegInfo makes the following assignments :
Rkp.ID := t Rkp.Level := l
Rkp.Name1 := s1 Rkp.ExpYear := ey
Rkp.Name2 := s2 Rkp.ExpMonth := em
Rkp.Name3 := s3 Rkp.ExpDay := ed
Rkp.Message := m Rkp.Key := k
Since the values in the Rkp record may be accessed directly, you will not
normally need SetRegInfo. However, if you are using MakeKey and/or ValidKey
with temporary values, you might want to use SetRegInfo as a "short-cut"
method of assigning those values to the Rkp record.
Example :
Write('Enter your customer ID : ');
ReadLn(i);
Write('Enter your name : ');
ReadLn(n);
Write('Enter your address (line 1) : ');
ReadLn(a1);
Write('Enter your address (line 2) : ');
ReadLn(a2);
Write('Enter your phone number : ');
ReadLn(p);
Write('Enter your registration key number : ');
ReadLn(k);
WriteLn;
If Not ValidKey(n,a1,a2,0,k) then { registration levels not used }
WriteLn('Registration key number invalid!')
Else
SetRegInfo(i,n,a1,a2,p,0,0,0,0,k);
In the above example, the existing registration information (in the Rkp
record) will not be changed if the registration key is invalid. Note also
that this example uses Rkp.ID (set to the value of the variable i) to store
a customer number, and Rkp.Message (set to the value of the variable p) to
store the user's phone number. These values are not used in the encryption
of keys and, therefore, may be used to store any information that you want.
11.13 - CreateKey
Procedure CreateKey;
The procedure CreateKey will use the encode functions defined with SetEncode
to generate a key encrypted from Rkp.Name1, Rkp.Name2, Rkp.Name3, Rkp.Level,
Rkp.ExpYear, Rkp.ExpMonth (and Rkp.ExpDay, if UseExpDays is True) with an
embedded expiration date, returning the resulting key in Rkp.Key. If you
don't wish to use registration levels, simply set Rkp.Level to 0 before
calling CreateKey. If you don't wish to use expiration dates, simply set
Rkp.ExpYear, Rkp.ExpMonth and Rkp.ExpDay to 0 before calling CreateKey.
CreateKey sets the following result code, which will be returned by
subsequent calls to RkpError :
BadTPU - RKPLUS.TPU is corrupt or has been tampered with
InvalidParameter - Rkp.ExpYear, Rkp.ExpMonth or RkpDay is invalid
Example :
Write('Enter name : ');
ReadLn(Rkp.Name1);
Write('Enter company : ');
ReadLn(Rkp.Name2);
Write('Enter phone number (XXX) XXX-XXXX : ');
ReadLn(Rkp.Name3);
Rkp.Level := 0; { registration levels are not being used }
Rkp.ExpYear := 0; { expiration dates are not being used }
Rkp.ExpMonth := 0;
Rkp.ExpDay := 0;
CreateKey;
WriteLn;
If RkpOK then
WriteLn('Registration key is ',Rkp.Key);
This will display a warning message and then prompt for a name, company
name, and phone number. CreateKey is called and the key is returned in
Rkp.Key, which is then displayed, if no error has occurred.
Note: It is possible to use CreateKey to create keys and then to store the
contents of the Rkp record into your own configuration file (instead of
using SaveRegInfo) and then read the information into your programme and use
VerifyKey to verify that the key is valid (rather than using GetRegInfo).
This way you can keep registration information in your own configuration
file with other programme information, rather than in its own key file. If
using this method, its important that you save Rkp.Name1 (as well as
Rkp.Name2, Rkp.Name3 and/or Rkp.Level, if used), so that keys will be built
correctly. It is not necessary to save Rkp.ExpYear, Rkp.ExpMonth or
Rkp.ExpDay, since the expiration date is binary-encoded in the key number
and extracted by any call to VerifyKey.
11.14 - VerifyKey
Procedure VerifyKey;
The procedure VerifyKey will use the encode functions defined with SetEncode
to generate a key encrypted from Rkp.Name1, Rkp.Name2, Rkp.Name3 and
Rkp.Level; and compare the resulting key to Rkp.Key, setting Rkp.Registered
to True if the key is valid and not expired. Rkp.ExpYear, Rkp.ExpMonth (and
Rkp.ExpDay, if UseExpDays is True) will be set to the expiration date
encoded in the key. If you don't wish to use registration levels, simply
set Rkp.Level to 0 before calling VerifyKey.
VerifyKey sets the following result codes, which will be returned by
subsequent calls to RkpError :
InvalidKey - Key is not valid
ExpiredKey - Key has expired
BadTPU - RKPLUS.TPU is corrupt or has been tampered with
Example :
Write('Enter your name : ');
ReadLn(Rkp.Name1);
Write('Enter your BBS name : ');
ReadLn(Rkp.Name2);
Write('Enter your FidoNet address : ');
ReadLn(Rkp.Name3);
Write('Enter your registration key : ');
ReadLn(Rkp.Key);
Rkp.Level := 0; { registration levels are not used }
VerifyKey;
If Not RkpOK then Begin
Case RkpError of
ExpiredKey : WriteLn('This key has expired!');
InvalidKey : WriteLn('This key is invalid!');
Else WriteLn('Error ',RkpError);
End;
Halt(1);
End;
This programme will prompt the user to enter a name, BBS name, FidoNet
address, and a registration key. If the registration key has expired,
"This key has expired!" will be displayed. If the registration key is
invalid, "This key is invalid!" will be displayed. Otherwise, if an error
has occurred, an error message will be displayed. In any case where the key
is not validated, the programme will halt with an errorlevel of 1.
11.15 - GetRegInfo
Procedure GetRegInfo;
GetRegInfo will read the key file (if it exists) and set the value of the
following variables :
Rkp.Name1 - set to primary registration name
Rkp.Name2 - set to secondary registration name
Rkp.Name3 - set to third registration name
Rkp.Level - set to registration level (0 if not used)
Rkp.ExpYear - set to expiration year (0 if not used)
Rkp.ExpMonth - set to expiration month (0 if not used)
Rkp.ExpDay - set to expiration day (0 if not used or UseExpDays is False)
Rkp.Key - set to 12 digit alphanumeric registration key
GetRegInfo would generally be called near the beginning of a programme
(after SetEncode has been called to define the encode functions and
SetKeyFile has been called to define the key file).
GetRegInfo sets the following result codes, which will be returned by
subsequent calls to RkpError :
ExpiredKey - Registration key has expired
InvalidKey - programme is registered with an invalid key
InvalidFile - File is not a RkPlus(tm) registration key file
BadTPU - RKPLUS.TPU is corrupt or has been tampered with
Example :
GetRegInfo;
If Rkp.Registered then
WriteLn('Registered to ',Rkp.Name1);
GetRegInfo will read the key file (specified in an earlier call to
SetKeyFile). If the programme is registered, Rkp.Registered will be True and
the programme will display the name of the person that the programme is
registered to.
11.16 - SaveRegInfo
Procedure SaveRegInfo;
The procedure SaveRegInfo will use the encode functions defined with
SetEncode to generate a key encrypted from Rkp.Name1, Rkp.Name2, Rkp.Name3,
Rkp.Level, Rkp.ExpYear, Rkp.ExpMonth (and Rkp.ExpDay, if UseExpDays is
True). It will them compare the resulting key with Rkp.Key and write the
contents of the Rkp record to the keyfile. If you don't wish to use
registration levels, simply set Rkp.Level to 0 before calling SaveRegInfo.
If you don't wish to use expiration dates, simply set Rkp.ExpYear,
Rkp.ExpMonth, and Rkp.ExpDay to 0 before calling SaveRegInfo.
SaveRegInfo sets the following result codes, which will be returned by
subsequent calls to RkpError :
InvalidKey - Key is not valid
BadTPU - RKPLUS.TPU is corrupt or has been tampered with
Example :
Write('Enter your name : ');
ReadLn(Rkp.Name1);
Write('Enter your company name : ');
ReadLn(Rkp.Name2);
Write('Enter your registration key : ');
ReadLn(Rkp.Key);
Rkp.Level := 0; { registration levels not used }
Rkp.ExpYear := 0; { expiration dates not used }
Rkp.ExpMonth := 0;
Rkp.ExpDay := 0;
SaveRegInfo;
If Not RkpOK then
WriteLn('Invalid Key or File Error. Programme not installed.');
This programme will prompt the user for a name, company name, and a
registration key. SaveRegInfo will then be called. If Rkp.Registered is not
True, then an error occurred and no key file was written (the programme
displays 'Invalid Key or File Error. Programme not installed.'). Otherwise,
the key file was written.
11.17 - BrandRegInfo
Procedure BrandRegInfo;
The procedure BrandRegInfo will use the encode functions defined with
SetEncode to generate a key encrypted from Rkp.Name1, Rkp.Name2, Rkp.Name3,
Rkp.Level, Rkp.ExpYear, Rkp.ExpMonth (and Rkp.ExpDay, if UseExpDays is
True). It will them compare the resulting key with Rkp.Key and brand the
contents of the Rkp record to the EXE file. If you don't wish to use
registration levels, simply set Rkp.Level to 0 before calling BrandRegInfo.
If you don't wish to use expiration dates, simply set Rkp.ExpYear,
Rkp.ExpMonth, and Rkp.ExpDay to 0 before calling BrandRegInfo.
BrandRegInfo sets the following result codes, which will be returned by
subsequent calls to RkpError :
InvalidKey - Key is not valid
InvalidFile - EXE file is NOT an RkPlus(tm) 3.x file
BadTPU - RKPLUS.TPU is corrupt or has been tampered with
Example :
Write('Enter your name : ');
ReadLn(Rkp.Name1);
Write('Enter your company name : ');
ReadLn(Rkp.Name2);
Write('Enter your registration key : ');
ReadLn(Rkp.Key);
Rkp.Level := 0; { registration levels not used }
Rkp.ExpYear := 0; { expiration dates not used }
Rkp.ExpMonth := 0;
Rkp.ExpDay := 0;
BrandRegInfo;
If Not Rkp.Registered then
WriteLn('Invalid Key or File Error. Programme not branded.');
This programme will prompt the user for a name, company name, and a
registration key. BrandRegInfo will then be called. If Rkp.Registered is
not True, then an error occurred and the EXE file was not modified (the
programme displays 'Invalid Key or File Error. Programme not branded.').
Otherwise, the EXE file was modified to include the registration
information.
Note: BrandRegInfo has NOT been tested with any EXE-compression programmes.
Because of the way that RkPlus(tm) searches for it's ID stamp, it will most
likely NOT work on "compressed" files. Calls to BrandRegInfo (when the EXE
file set with SetKeyFile has been "compressed") will probably set the result
code of InvalidFile.
11.18 - SetFileEnc
Procedure SetFileEnc(ef : FileFuncType);
This procedure is used to specify the File Encoding Function that will be
used by RkPlus(tm) to "scramble" key files (see KeyFileCode). It is
automatically set by Rkp2Enc and Rkp3Enc. You will only need to use
SetFileEnc if you are using user-written encoding functions.
12.0 - Additional Information On RkPlus(tm)
For more information on using RkPlus(tm), see the sample Turbo Pascal (tm)
programmes that are distributed with the archive, or contact me at any of
the locations listed below.
13.0 - RkPlus(tm) Source Code Availability
Starting with version 3.0, the source code to RkPlus(tm) (as well as the
smaller rKey unit) is available to licenced users. Since SetEncode was
added, allowing programmers to write their own encoding functions, the
security of programmes written with RkPlus(tm) are no longer compromised by
releasing the source code. See REGISTER.USA or REGISTER.EUR for more
information.
14.0 - What's Next For RkPlus(tm)?
I am currently working on WriteRegTag and ReadRegTag, which will allow
registration information to be written to and read from the end of existing
files (text files, compressed EXE files, etc).
I am also working to streamline the user-written encoding process, to make
it easier for programmers to write their own encode units.
I still hope to eventually release QuickBASIC(tm) and C versions of
RkPlus(tm), but limitations of BASIC and my limited knowledge of C have
caused it to be a more daunting task than I had anticipated.
If you have any suggestions for features that you'd like to see in future
versions of RkPlus(tm), feel free to contact me via any of the methods
below. I welcome questions, comments and suggestions of any kind.
15.0 - ShareWare Notice And Registration
RkPlus(tm) is Shareware. You may copy and distribute the RKPLUS33 archive
freely. All I ask is that you include all of the original files,
unmodified, and that you do not charge for the distribution of RkPlus(tm)
itself. If you use RkPlus(tm) to develop software, you are required to
register BEFORE releasing it (see REGISTER.USA or REGISTER.EUR for
registration information).
There are no royalties for the distribution of programmes that are written
with RkPlus(tm). A single registration fee entitles you to write and
distribute any number of programmes using RkPlus(tm).
Questions, comments, and suggestions are welcome.
Send US Mail to:
Serious Cybernetics
6804 Belton Place
Lula, GA 30554-2622 USA
You may also contact me at either of the BBS's listed below, or via the
Serious Cybernetics Echo on CyberNet.
16.0 - RkPlus(tm) Support
The latest version of RkPlus(tm) can always be downloaded from either of
our support BBS's below.
In the United States and Canada :
P h o e n i x S t a r F i g h t e r B B S
The Home of "Serious Cybernetics" - FidoNet/CyberNet 1:3616/20
(404) 869-3410 - Lula, Georgia, USA - 24 Hour Service (excl NMH)
Supporting 3/12/24/48/96/144/HST/v32/v32b/v42/v42b via USR HST/DS Modem
Sysops: Danny Sosebee and Scott Davis
All Users Welcome! Immediate Access!
We have the following "magic" filenames set up for FidoNet file requests :
"FILES" will request the current master file listing (updated nightly)
"CYBER" will request the current CyberNet info pack and file list
"RKPLUS" will request the latest version of RkPlus(tm)
"RKHELP" will request the latest version of RkPlus(tm) Help
"RKP" will request the latest version of ALL RkPlus(tm) files
In the United Kingdom and Europe :
F r o n t i e r s BBS
European Home of "Serious Cybernetics" - FidoNet/CyberNet 2:440/63
Tel +44-(0)737-778607 - 24 hours Per Day (excl NMH)
Sysop: Dave Parker
All Users Welcome!
17.0 - Credits
I'd like to thank Danny Sosebee (Sysop of Phoenix StarFighter BBS) for
allowing me to distribute my software through his BBS, as well as for
helping me rewrite and "clean-up" the documentation and help files. Also,
I'd like to thank Ed Ivey (Sysop of Ed's Place BBS - 404-532-1978 - FidoNet
Node 1:3616/1) for his continued support and assistance with my little
software "projects". I would also like to thank Dave Parker (Sysop of
Frontiers BBS) for volunteering to become our European distribution, support
and registration site.
In addition, I'd like to thank the following users of RkPlus(tm) who have
made valuable suggestions :
Nick Herceg - Made MANY excellent suggestions (too many to list here), which
led directly to the rewriting of rKey as RkPlus(tm). [2.0]
Mike Janke - The FIRST user to register RkPlus(tm) (thanks, Mike!). He also
suggested that the key file extension (previously .REG) be definable. [2.3]
Luke Kolin - Suggested a definable key file size (padded with random
characters) to confuse potential hackers. [2.3]
Mats Engstrom - Found and reported bugs in the version 2.x encoding
functions and in the key validation routine when the expiration month was
set to 12 (December). [2.4]
Tom Thayer - Reported the naming conflict between the registration record
and some programmes/units that use Reg to contain registers. Also, made me
aware of how vulnerable RKPLUS.TPU was to "tampering". [2.4]
Aaron Blanton - Made me aware of the possibility of programmers/hackers
examining the EXE file to determine the constants used in the version 2.x
encoding functions. [2.4] This led directly to the encryption method used
in Rkp3Enc and programmer-definable encode functions. [3.0]
Joe Dabrowski - Suggested that I allow the key file to be "scrambled"
(KeyFileCode). [3.0]
Rand Nowell and Markus Bartsch - Found and reported a bug in the version 3.x
expiration date algorythm when UseExpDays was set to True. [3.2] Rand also
helped me isolate and resolve a related bug in VerifyKey. [3.3]
Finally, I'd like to thank all of the REGISTERED users of RkPlus(tm) whose
support keeps the ShareWare concept alive.
18.0 - Turbo Pascal (tm) Units from Serious Cybernetics
The following Turbo Pascal (tm) units are available from Serious
Cybernetics :
CmdParse 1.02 - TP55/60/TPW10/15 Command Line Parsing Unit
rKey 1.7 - TP50/55/60 Simple Registration Key Unit
RkPlus 3.3 - TP50/55/60/70/TPW10/15/BP70/SBP+ Enhanced Reg Key Unit
StrLib 1.4 - TP String Library Unit (with source)
19.0 - Other Recommended Turbo Pascal (tm) Units
I use units from Object Professional (tm) from TurboPower Software in almost
every programme that I write, and strongly recommend it (as well as any
other units from Turbo Power) to any Turbo Pascal (tm) programmer.
ObjectPro has been, for me, the single most useful collection of general
purpose units that I have ever run across.
20.0 - Copyright Notices
RkPlus (c) 1991-93 Serious Cybernetics
Rkp2Enc (c) 1990-93 Serious Cybernetics
Rkp3Enc (c) 1993 Serious Cybernetics
CmdParse (c) 1992-93 Serious Cybernetics
rKey, StrLib (c) 1990-92 Serious Cybernetics
Turbo Pascal (c) 1983-89 Borland International
Borland Pascal (c) 1983-93 Borland International
Stony Brook Pascal+ (c) 1987-93 Stony Brook Software
Object Professional (c) 1989 TurboPower Software
Microsoft Windows (c) 1985-92 Microsoft Corporation
QuickBASIC (c) 1982-88 Microsoft Corporation