
Are your programming skills producing marketable software ?  

If so, you will most likely require that each copy be registered by any prospective user.

You may be distributing 'freebies' and simply wish users to identify themselves with their copy of your software since you are seeking fame or noteriety rather than fortune !

Most, if not all 'shareware' programs include unregistered/registered status code in one way or another. But how can we introduce a feature of this sort using only Visual Basic ?  Well, we could maintain a text file of a type '.ini', '.cnf', '.dat', etc., using Windows' API functions or VB's file handling capabilities but this is not very satisfactory since we all know how to edit text files and subsequently cheat.

A better way would be to hold details in an application's executable module which would relate to it's registered/unregistered status.  These would be inspected on running and would allow an appropriate response by the program.  This latter approach is what the registration demo, REGISTER.EXE, achieves.

Even with this approach it is not beyond the scope of some to edit the module.  It would be quite possible to load it into the likes of the Norton Utilities  Disc Editor, make a search of the code when viewed in ascii format and edit/save the related information (providing you were able to identify it).  Nevertheless, it's as good as we'll get with Visual Basic (and a couple of Windows' API functions), and we could utilise encryption of one sort or another to disguise the relevant bytes of information.  REGISTER.EXE however, for the purposes of demonstration, is straight forward and doesn't include encryption.

To interact with the demo now, RUN THE COMPILED VERSION SUPPLIED !  i.e. 'register.exe'.  In VB Run Time the project runs as if it were registered which is just as well since if you attempt to register (write to the executable module), in VB Run Time mode you will cripple VB.  Afterwards, (or now if you wish), read on to find out why.  When the demo runs you are prompted to register. The 'Register Later' button will allow continued use in an unregistered state.  You will be reminded to register every 15 minutes and each time you run the demo.  The 'Quit' button is self explanatory.  The "Register Now' button will reveal a text box and an 'OK' button.  The text box contains the specimen serial or code number and you need only activate the 'OK' button to enter it.  Following this (assuming you haven't changed the number), you are asked to provide your name and a company name or your status.  A user name is mandatory (Try the 'OK' button without it).  When done, you will see the demo main form.  If you now click the About menu, you will see the registration details (or default information if you didn't register).  The Explain menu will run this text file in NotePad.  The Register menu will allow registration without re-running the demo or the superb VB application if it was one.


The project files for the demo are as follows:

Register.mak
Main.frm
About.frm
Reg.frm
User.frm
Module1.bas

A further set of project files relate to DEFAULTS.EXE and are as follows:

Defaults.mak
Defaults.frm

The purpose of DEFAULTS.EXE will become clear later and suffice for now to say that it must remain in the same directory as REGISTER.EXE until it has been run once.


IN A NUTSHELL !

Succinctly, creation is as follows:

1.  Declare the required number of Global Constants in a VB module to create the necessary space for the information you wish to read/write within your program's executable file.

2.  Compile your executable module and use a disc editor to identify the byte offsets in the module for this information.  (I used Norton Utilities  DiskEdit).  Insert the byte offsets into your project files and re-compile without adding or removing any other code.

3.  Use the two Windows API functions (see later) to obtain the path and filename of your program's executable file (no matter where it is or what it is called).

4.  Open the file for binary read/write.

5.  Retrieve the registration information using the byte offsets obtained previously and respond according to what it is.

6.  Write registration details to the module when appropriate.

AND THAT'S IT !

BUT, AS A VB USER, YOU NEED TO KNOW MORE THAN THIS -

For programmatic information study the project files which are fully annotated.

What you may not know, and what I discovered at the cost of much time and frustration is what follows primarily:

When declaring the Global Constants, you attach their values (in this instance) in the form of strings.  i.e.

Global Const UserName$ = "A DEFAULT NAME STRING    " (25 Chars in my case).

If, following compilation, you then view the executable module in a disc editor, you will, as you might expect, see the string data at an arbitrary location (you would probably perform a search operation).  When you run either the project in VB Run Time or the compiled executable file itself and retrieve the relevant bytes, YOU GET GARBAGE !  To see this, run the project in VB.  It will run as if it were a registered version.  Click on the About menu and you will see this garbage displayed.  The program did not find the default strings as we expected and ran as a registered version.


IMPORTANT!!!

Attempts to have the project write strings in VB Run Time mode if necessary, revealed that Visual Basic TAKES GREAT EXCEPTION TO PROGRAMS WHICH ATTEMPT TO WRITE TO THEIR OWN EXECUTABLE MODULE whilst in project format in VB Run Time and will cause corruption which only becomes evident the next time you attempt to run VB.  Windows will report that there is insufficient memory to run VB.  My only solution was to completely re-install it. (Several times at 35.mins each until I discovered that the foregoing was the cause).  FURTHER, if you have been writing to your own executable module in VB Run Time AND YOU THEN ATTEMPT TO COMPILE AN EXE FILE, your machine will crash.

To successfully create an executable file, load the project but DO NOT RUN IT!  Create the executable file immediately.  If you modify the project files in any way, you must ensure that you check the resultant executable file to ascertain the location of the relevant string space.  It could well have changed and, if so, you will need to adjust the byte offsets in the the project files' code and re-compile.  It would be a good idea to leave the addition of a registration feature to your fame and fortune application until last.

Because the executable module also runs initially as if it were registered, (it also retrieves the same garbage), a solution was required.

My solution to this was DEFAULTS.EXE

This project has only 1 form and no objects.  The form 'load' event opens App.Path & "\register.exe", (hence the need for it to reside in the same directory) and writes our default strings for us.  THIS ONLY NEEDS TO BE DONE ONCE!  The executable module then behaves properly thereafter and we can copy and distribute as many as we wish.

To reset the demo executable module to unregistered status after each registration excercise, simply double-click DEFAULTS.EXE first and then run the demo again.


WINDOWS API FUNCTIONS

These declarations must be entered completely on one VB line at whatever level is appropriate.

Declare Function GetClassWord% Lib "User" (ByVal hWnd As Integer, ByVal nIndex As Integer)

GetClassWord will retrieve the module type for your application

Parameter
hWnd

This is the handle of your application's window class

Paremeter
nIndex

This is an integer number and when -16, will get the handle to the module for this class


Declare Function GetModuleFileName% Lib "Kernel" (ByVal hWnd As Integer, ByVal filname As String, ByVal nSize As Integer)

GetModuleFileName will retrieve the path and filename for your application's module

Parameter
hWnd

This is the handle of your application's window class

Parameter
filname

This is the buffer you have dimensioned to hold the path and filename returned.  It must always be at least the length of the returned string + 1 (null character).

IMPORTANT NOTE !  It is up to you to ensure this buffer is large enough to hold the longest string that is ever likely to be returned.  If it is not, and a longer string is returned, it will overwrite code following the buffer and is one of the simplest ways of creating a Windows General Protection Fault ('GPF') which will at least cause your program to crash.

Parameter
nSize

The number of characters you wish returned.  The size of this and 'filname' will depend on the depth of nesting in your disc directory structure.


The following function, which is not really necessary for the purposes of the demo, can tell you if an application is already running.  In our case it will look for Windows Notepad.  It is declared in the General/Declarations section of frmMain.  Either or both of the parameters will work.

Declare Function FindWindow% Lib "user" (ByVal lpClassName As Any, ByVal lpCaption As Any)

Parameter
lpClassName

The window class name which just happens to be "NotePad".  VB Forms have the class name of "ThunderForm"

Parameter
lpCaption

This is the Caption in the title bar of an application's main form and, whilst not case sensitive, it must be represented exactly as displayed.


A MUCH REPEATED TIP !

Functions and procedures in DLL library files get really 'uppity' when passed invalid parameters and will usually react by destroying some, if not all of your machines' binary logic functionality, and may render it brain dead until reset.

END
