New Style |
Top Previous Next |
A new style of examples is introduced in version 5.1.3 in order to make easier the configuration used in conjunction with a new utility called configurator that allows to generate configuration code and then insert it into the code of the applications. With minor variations, the operation of the examples is the same as in previous versions. Below you can see a screenshot that shows the folders of the examples presented with this new style:
Here we describe only the example 1a in the OLM advanced version, which is the most complete example, once you become familiar with this example, you can easily understand the rest of the examples included in the package. This topic only describe the code and its functionality, for more information see the old-style examples that describe practices carried out step by step.
Example 1a
The following is a list of files that make up this example:
project1.dpr unit1.dfm unit1.pas regist.dfm regist.pas wait.dfm wait.pas avlockunit.pas conf.inc
project1.dpr
It is the project file. Note in the code below the only line added in order to allow to AVlock to control the application. Here is called the DoRegister procedure, which displays a form for the user to register and finally according the registration status decide whether to continue executing the program or terminate it.
program Project1;
uses Forms, Unit1 in 'unit1.pas' {Form1}, Regist in 'Regist.pas' {RegForm}, avlockunit in 'avlockunit.pas', wait in 'wait.pas' {WaitForm};
{$R *.res}
begin Application.Initialize; Application.CreateForm(TForm1, Form1); Form1.DoRegister(False); //<-- add only this line here Application.Run; end.
In order to use AVLock with your own project, simply add the line mentioned above, then copy the rest of the files in the example to your project and link to it. Below you can see the files that make up this example:
unit1.dfm, unit1.pas
In this example, files Unit1.pas and unit1.dfm make up the project's main form. Below you can see the source code of this unit, there is only one procedure for each of the buttons that were placed on the form, and these refer to some features found in avlockunit.pas.
Two references was added to the uses clause; AVLockS5 and avlockunit, these refer to the AVLock component and the avlockunit.pas unit.
unit Unit1;
interface
uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls, AVLockS5, avlockunit;
type TForm1 = class(TForm) BtnReg: TButton; Label1: TLabel; Label2: TLabel; BtnFree: TButton; BtnRestricted: TButton; procedure BtnRegClick(Sender: TObject); procedure BtnRestrictedClick(Sender: TObject); procedure BtnFreeClick(Sender: TObject); private { Private declarations } public { Public declarations } end;
var Form1: TForm1;
implementation {$R *.dfm}
procedure TForm1.BtnFreeClick(Sender: TObject); begin showmessage('This Feature is always Available'); end;
procedure TForm1.BtnRestrictedClick(Sender: TObject); begin if (keydata.Status = Registered) then showmessage('This Feature is currently Available') else showmessage('this Feature is currently Unavailable'); end;
procedure TForm1.BtnRegClick(Sender: TObject); begin DoRegister(True); end;
end.
Let's now analyze the code for each one of these buttons:
[Free Features]: Just shows a message that through this button takes you to free use functions.
[Restricted Features]: This code uses an if statement evaluates the Boolean expression (keydata.Status = Registered) and according the result (true/false) displays the appropriate message. All new for you in this code is the expression (keydata.Status = Registered, the keydata record is a structure defined in the AVLock component, containing all information about the current registration status, here we reference the Status field that can take one of the following values (Unregistered, Moved, Expired, Registered). This way we can enable / disable the access to the functions allowed only to registered users.
[Register Now]: This button accesses the registration form (regist.dfm, regist.pas) is accessed with the function DoRegister (True) in the same way we did in the project file, with the difference that we now use the parameter "true" that indicates that is invoked unconditionally.
regist.dfm, regist.pas These are the files that makes up the registration form. Below is a view of this form:
These are the controls used in this form:
lstatus: TLabel; Used to display the current registration status.
EdIcode: TEdit; Used to display the corresponding Installcode the computer that is running the application.
EdName: TEdit; Used for the user to enter his name.
EdCompany: TEdit; Used for the user to enter his Company.
EdEmail: TEdit; Used for the user to enter his email address.
EdOther: TEdit; Used for the user to enter his postal address.
EdKey: TEdit; Used for the user to enter the Registration Key.
BtnLoad: TButton; Allows the user to enter the Registration Key from a file.
OpenDialog1: TOpenDialog; Called from BtnLoad to select the file with the Registration Key.
BtnReg: TButton; Performs the Registration task using the Key entered by the user.
BtnContinue: TButton; Exits the registration form.
The following buttons should not be placed in the final version of your application. Its purpose is to allow you to do practice with the component and to test the various features thereof.
BtnTrial: TButton; Allows to start the trial period.
BtnCheckDate: TButton; Allows to verify the system date through internet.
BtnCheckAndFix: TButton; Allows to verify the system date through internet, then fix it if needed.
BtnSynch: TButton; Allows to synchronize the local registration data from the OLM (Online License Manager). In this case using the OnlineSynch function.
BtnFull: TButton; Allows to synchronize the local registration data from the OLM (Online License Manager). In this case using the OnlineFullSynch function.
BtnRenew: TButton; Allows to register a new key generated by the OLM. So, you should enter the proper values for the new key into the OLM record using the control panel, then set (Paid='Y'), then, when the user clicks this button, the new key is generated and saved into the OLM and send to the application to be saved also locally. Otherwise if (Paid='N') the action is similar to OnlineSynch. You could put a button like this in your app in order to allow to the user to activate a new key when you authorize it from the OLM or perhaps you could automatize this process calling this code each time the app starts in order to register a new key every time it is available.
BtnRemove: TButton; Allows to remove the registration data from the OLM and locally.
BtnInstances: TButton; Shows the instances that are running at the time, provided it is established InstancesCtrl: = True;
Below is the source code of this unit. Note that in the implementation clause we added a reference to avlockunit. Also note that each button calls procedures and functions declared and defined in the avlockunit unit.
unit Regist;
interface
uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls;
type TRegForm = class(TForm) Panel1: TPanel; Image1: TImage; Image2: TImage; Panel2: TPanel; BtnContinue: TButton; EdKey: TEdit; Panel3: TPanel; LRegInfo: TLabel; LToReg: TLabel; BtnReg: TButton; Label1: TLabel; lstatus: TLabel; Panel4: TPanel; Label3: TLabel; BtnRemove: TButton; Panel5: TPanel; Label2: TLabel; EdIcode: TEdit; Label39: TLabel; BtnTrial: TButton; BtnCheckDate: TButton; BtnCheckAndFix: TButton; Label4: TLabel; BtnRenew: TButton; BtnSynch: TButton; Label5: TLabel; LName: TLabel; LCompany: TLabel; Label34: TLabel; Label6: TLabel; EdName: TEdit; EdCompany: TEdit; EdEmail: TEdit; EdOther: TEdit; BtnFull: TButton; BtnLoad: TButton; OpenDialog1: TOpenDialog; BtnInstances: TButton; procedure BtnContinueClick(Sender: TObject); procedure BtnRegClick(Sender: TObject); procedure BtnRemoveClick(Sender: TObject); procedure BtnTrialClick(Sender: TObject); procedure BtnCheckDateClick(Sender: TObject); procedure BtnCheckAndFixClick(Sender: TObject); procedure BtnRenewClick(Sender: TObject); procedure BtnSynchClick(Sender: TObject); procedure BtnFullClick(Sender: TObject); procedure BtnLoadClick(Sender: TObject); procedure BtnInstancesClick(Sender: TObject); private { Private declarations } public { Public declarations } end;
implementation uses avlockunit; {$R *.DFM}
procedure TRegForm.BtnContinueClick(Sender: TObject); begin modalresult:=mrOk; end;
procedure TRegForm.BtnLoadClick(Sender: TObject); var Ftxt: TextFile; s: string; begin if opendialog1.Execute then begin AssignFile(Ftxt, opendialog1.FileName); Reset(Ftxt); ReadLn(Ftxt, s); EdKey.Text := trim(s); CloseFile(Ftxt); end; end;
procedure TRegForm.BtnRegClick(Sender: TObject); var s:string; begin RegKey(EdKey.Text, edname.Text, edcompany.Text, edemail.Text, edother.Text, s); end;
procedure TRegForm.BtnTrialClick(Sender: TObject); var s:string; begin showmessage(StartTrial(edname.Text ,edcompany.Text ,edemail.Text ,edother.Text, s)); if (s<>'') then lstatus.Caption :=s; end;
procedure TRegForm.BtnRenewClick(Sender: TObject); var s:string; begin showmessage(Renew(s)); if (s<>'') then lstatus.Caption :=s; end;
procedure TRegForm.BtnSynchClick(Sender: TObject); var s:string; begin showmessage(Synch(s)); if (s<>'') then lstatus.Caption :=s; end;
procedure TRegForm.BtnFullClick(Sender: TObject); var s:string; begin showmessage(FullSynch(s)); if (s<>'') then lstatus.Caption :=s; end;
procedure TRegForm.BtnInstancesClick(Sender: TObject); begin showinstances; end;
procedure TRegForm.BtnCheckDateClick(Sender: TObject); begin checkdate; end;
procedure TRegForm.BtnCheckAndFixClick(Sender: TObject); begin checkandfixdate; end;
procedure TRegForm.BtnRemoveClick(Sender: TObject); var s:string; begin showmessage(RemoveReg(s)); lstatus.Caption :=s; end;
end.
avlockunit.pas It contains the basic functions of the component configuration. We will discuss each of the parts of this code. The interface section have the following declarations of constants and variables:
const ACTION_DATE_TURNED_BACK: integer = 1; //0:No action, 1:Fix the date ACTION_EXPIRED : integer = 2; //0:no action, 1:nag screen, 2:terminate EXPIRY_DAYS_TO_WARN : integer = 15; USER_DATA_REQUIRED : boolean = True;
var AVLock : TAVLockS5; keydata : TKeyData;
ACTION_DATE_TURNED_BACK defines what should be done when the user system date is turned back, presumably trying to reuse an expired trial period.
ACTION_EXPIRED defines what should be done when the application is been expired.
EXPIRY_DAYS_TO_WARN defines the number of days before expiry when should be displayed the registration form when the app starts.
USER_DATA_REQUIRED defines whether the user is required to enter your personal information before you start the trial period or register.
The AVLock variable is the AVLock component that should be created in the initialization section and destroyed in the finalization section.
The keydata variable is a record structure of type TKeyData, defined in the component (avlocks5.pas file) to contain all the information about the registration status of the component. Below you can see its definition:
TRegStatus = (Unregistered, Moved, Expired, Registered); TKeyType = (Trial, Temporal, Permanent, Unregister, UnregisterAll);
TKeyData = record Status: TRegStatus; KeyType: TKeyType; Startdate: TDate; EndDate: TDate; Days: word; DaysLeft: word; Users: byte; Instances: byte; Primary: Boolean; DateBacked: Boolean; TooManyInstances: Boolean; Values: string; Key: string; ICodeP: string; InstallCodep: string; end;
The AVLock variable is created into the initialization section.
initialization AVLock:=TAVLockS5.Create(nil); with AVLock do begin {$I conf.pas} end;
With the statement {$I conf.pas} it is inserted the content of the conf.pas file with the configuration code for the component, generated with the configurator utility. Below is the code used for this example:
InstallCodeSources := Machine_Data; MachineSources := [System_UUID,BaseBoard_SN]; InstancesCtrl := False; RegPath := ExeDir; RegFolder := ''; EncryptionKey := hextoascii('616263313233');//abc123 EncryptionKey2 := hextoascii('78797A333231');//xyz321 AppID := strtoint(hextoascii('3132333031'));//12301 AppName := hextoascii('4D79417070');//MyApp AppVersion := hextoascii('312E302E30');//1.0.0 WebHost := hextoascii('7777772E61762D736F66742E636F6D');//www.av-soft.com TimeHost := hextoascii('74696D652D612E6E6973742E676F76');//time-a.nist.gov OlmPath := hextoascii('2F6F6C6D3531');///olm51 OlmBasicScript := hextoascii('62617369636F6C6D2E706870');//basicolm.php OlmAdvScript := hextoascii('616476616E6365646F6C6D2E706870');//advancedolm.php ACTION_DATE_TURNED_BACK := 1; ACTION_EXPIRED := 1; EXPIRY_DAYS_TO_WARN := 15; USER_DATA_REQUIRED := True;
The above is the obfuscated version of conf.pas that has all the text values converted to hexadecimal, then, at runtime, it is converted to its original plain text using the hextoascii function. You could use this format to hide this information in the executable code. The plain text version is as follows:
InstallCodeSources := Machine_Data; MachineSources := [System_UUID,BaseBoard_SN]; InstancesCtrl := False; RegPath := ExeDir; RegFolder := ''; EncryptionKey := 'abc123'; EncryptionKey2 := 'xyz321'; AppID := 12301; AppName := 'MyApp'; AppVersion := '1.0.0'; WebHost := 'www.av-soft.com'; TimeHost := 'time-a.nist.gov'; OlmPath := '/olm51'; OlmBasicScript := 'basicolm.php'; OlmAdvScript := 'advancedolm.php'; ACTION_DATE_TURNED_BACK := 1; ACTION_EXPIRED := 1; EXPIRY_DAYS_TO_WARN := 15; USER_DATA_REQUIRED := True;
Next we look at the functions and procedures defined in the avlockunit.pas file:
function GetRegStatus:string;
This function gets information from local registration data (.avr file) then fills the different fields of keydata with this information, this is done with the line AVLock.GetKeyData (0, keydata), where 0 is the index used. When using a single key to control the application, the index should be 0. Below you can see the code for this function:
function GetRegStatus:string; var s:string; begin
AVLock.GetKeyData(0,keydata);
if keydata.DateBacked then case ACTION_DATE_TURNED_BACK of 1:if AVLock.OnlineCheckDate(true) then begin AVLock.restart; AVLock.GetKeyData(0,keydata); end else keydata.Status := Expired; 2:keydata.Status := Expired; end;
s:=''; case keydata.Status of Unregistered: s:='Not registered'; Moved : s:='Moved to another computer'; Expired : s:='Expired'; Registered : begin s:=''; case keydata.KeyType of Trial : s:=s+'Trial '+inttostr(keydata.Days)+' days - '+inttostr(keydata.DaysLeft)+' days left.'; Temporal : s:=s+'Temporal '+inttostr(keydata.Days)+' days - '+inttostr(keydata.DaysLeft)+' days left.'; Permanent : s:=s+'Permanent, no time limit.'; end; end; end; result:=s; end;
After obtaining the values for keydata, it checks if the system date was turned back, if this happens, the DateBacked field is set to True, then with the line "if keydata.DateBacked then" we perform the action established by ACTION_DATE_TURNED_BACK; 1) Calling the AVLock.OnlineCheckDate (true) fix the system date via the Internet, if the operation is successful, we restart the component with AVLock.restart and get new values for keydata calling again GetKeyData and if the operation did not success, the component state is set to expired. 2) When ACTION_DATE_TURNED_BACK is equals to 2, we directly set the status to expired.
Then we examine the value of keydata.Status and keydata.KeyType, to obtain so a string with a descriptive message that is returned as the result of the function. .
procedure wait(n:integer);
This procedure shows a box with a countdown to motivate the user to register (nag screen). Below you can see the code.
procedure wait(n:integer); var F:TWaitForm; reg:boolean; begin reg:=True; F:=TWaitForm.Create(nil); try F.cnt:=n; F.ShowModal; reg := (F.ModalResult = mrCancel); finally freeandnil(F); end; if reg then DoRegister(True); end;
procedure DoRegister(force:boolean);
This is the source code:
procedure DoRegister(force:boolean); var F : TRegForm; s, ic :string; ok:boolean; begin s:=GetregStatus; if AVLock.IsLocal and (force or (keydata.Status = Moved) or (keydata.DaysLeft < EXPIRY_DAYS_TO_WARN)) then begin AVLock.ReadAppData(False,ic,icode); F:=TRegForm.Create(nil); //Create the registration Form try F.EdIcode.Text := AVLock.InstallCode; F.EdName.Text := AVLock.UserName; F.EdCompany.Text := AVLock.Company; F.EdEmail.Text := AVLock.Email; F.EdOther.Text := AVLock.OtherCode; F.lstatus.Caption:=s; F.ShowModal; finally FreeAndNil(F); end; end; if (keydata.Status <> Registered) then begin case ACTION_EXPIRED of //0:no action, 1:nag screen, 2:terminate 1: wait(10); 2:begin showmessage('Not Registered'); application.Terminate; end; end; end; if AVLock.InstancesCtrl then begin if keydata.TooManyInstances then begin showmessage('Too many instances'); application.Terminate; end; if not AVLock.IsLocal and (AVLock.activeinstances.count < 2) then begin showmessage('This application must be run first from the server.'); application.Terminate; end; end; end;
We already used this procedure in the project file to display a form where the user can register and finally according the registration status decide whether to continue program execution or terminate it. It has a single boolean parameter "force" that If True, shows unconditionally the form, but if False, before to show the form, verifies the registration status and displays the form only if the following line turns out to be true.
if AVLock.IsLocal and (force or (keydata.Status = Moved) or (keydata.DaysLeft < EXPIRY_DAYS_TO_WARN))
Then, if true, with AVLock.ReadAppData(False,ic,icode); is read the user data from the local registration data, the form is created with F:=TRegForm.Create(nil);, the fields of the form are filled, then displays the form with F.ShowModal;
After close the form, the registration status is verified with (keydata.Status <> Registered),if the result is true, then executes the action corresponding to the value of ACTION_EXPIRED, if its value is 1, then the wait(10) screen is shown for 10 seconds countdown and else if its value is 2, shows the message "Not Registered" then ends the execution.
Next, the instances control is performed. Only if AVLock.InstancesCtrl is True.
procedure trimfields(var usrname,company,email,other:string);
It is a utilitarian procedure that applies the trim function to trim the variables passed as parameters.
function testfields(usrname,company,email,other:string):boolean;
This utilitarian function verifies that all user data passed as parameters are completed.
function StartTrial(usrname,company,email,other:string; var newstatus:string):string;
This function initiates the trial period. Applies only if the application is not registered (keydata.Status = Unregistered). Then, if USER_DATA_REQUIRED is true, it is verified that all user data fields have been filled and otherwise displays a message and leave the function. Finally, it calls the method OnlineStartTrial in order to initiate the trial period. If the operation was successful, the user data is stored into the OLM with AVLock.OnlineSaveUserData. The registration status is got again with GetRegStatus then passed through the newstatus variable. The message generated is passed as the function result. Below you can see the code:
function StartTrial(usrname,company,email,other:string; var newstatus:string):string; var n:integer; res:string; begin result:=''; if (keydata.status <> UnRegistered) then begin result:='Trial period already registered.'; exit; end; res:='00'; trimfields(usrname,company,email,other); if (keydata.Status = Unregistered) then begin if USER_DATA_REQUIRED then begin if not testfields(usrname,company,email,other) then begin result:='Please take a few moments to fill out your user data, then try again.'; exit; end; end; //(index,users,inst,days,values) res := AVLock.OnlineStartTrial(0,1,1,30,'000'); end; if (res='00') then begin AVLock.OnlineSaveUserData(usrname,company,email,other,0); newstatus:=GetRegStatus; result:='Trial started or synchronized successfully.'; end else result:='Could not start the trial period.'; end;
function RegKey(key,usrname,company,email,other:string; var newstatus:string):string;
This function registers a registration key in the OLM and locally. With the parameters are passed the registration key and user data. the user data passed is trimed then verified with testfields. Then the user data is stored with OnlineSaveUserData and the key registered with OnlineRegisterKey. The registration status is got again with GetRegStatus then passed through the newstatus variable. Is returned as function result a message describing the operation performed. Below you can see the source code:
function RegKey(key,usrname,company,email,other:string; var newstatus:string):string; var s1,s2: string; err:integer; begin result:=''; trimfields(usrname,company,email,other); if not testfields(usrname,company,email,other) then begin result:='Please fill out your user data then try again.'; exit; end; //Save Uuser data into the OLM and locally s1:=AVLock.OnlineSaveUserData(usrname,company,email,other,0); //register KEY into the OLM and locally if (s1='00') then begin s2:=AVLock.OnlineRegisterKey(trim(key)); if (s2='00') then begin result:='Key registered successfully'; newstatus:=GetRegStatus; end else result := Error2Str(s2); end else result := Error2Str(s1); end;
function Renew(var newstatus:string):string;
This function accesses the OLM and checks the Paid field, whether the field is equal to 'Y' (Paid = 'Y'), then generates a new registration key in the OLM and passes it to the application to be stored in local registration data. For more information see (Methods > OLM access methods)
function Renew(var newstatus:string):string; var res, msg:string; begin newstatus:=''; res := AVLock.OnlineRenew(0); if (res='00') or (res='') then newstatus:=GetRegStatus; if (res='00') then result:='User Data synchronized and Renewal Applied' else if (res='') then result:='User Data synchronized' else result:='ERROR: '+res; end;
function Synch(var newstatus:string):string;
This function performs a sync (OLM -> Local) using OnlineSynch. Get the user and registration data from the OLM and use it to replace the local registration data. For more information see (Methods > OLM access methods)
function Synch(var newstatus:string):string; var res:string; begin newstatus:=''; res := AVLock.OnlineSynch(0); if (res='00') then begin newstatus:=GetRegStatus; result:='User and Key data Synchronized'; end else result := Error2Str(res); end;
function FullSynch(var newstatus:string):string;
This function basically performs a sync (OLM -> Local) as in the previous case, but given the state of registration can act as StartTrial method (if you do not have an existing record in the OLM) or act as the method OnlineRenew when (Paid = 'Y'). For more information see (Methods > OLM access methods).
function FullSynch(var newstatus:string):string; var res, msg:string; begin newstatus:=''; res := AVLock.OnlineFullSynch(0); if (res='00') or (res='') then newstatus:=GetRegStatus; if (res='00') then result:='User and Key data synchronized and/or renewal applied and/or Trial Started' else if (res='') then result:='Synchronized User data only' else result := Error2Str(res); end;
procedure ShowInstances;
This procedure shows the instances of the app that are running.
procedure ShowInstances; var s:string; i:integer; begin if AVLock.InstancesCtrl then begin AVLock.Refresh; s:='There are active '+inttostr(AVLock.activeinstances.count)+' of '+ inttostr(keydata.Instances)+' Instances allowed'+#13#10 +'----------------------------------------------------------'+#13#10; for i:=0 to AVLock.activeinstances.count -1 do s:=s+AVLock.activeinstances[i]+#13#10; s:=s+'----------------------------------------------------------'; showmessage(s); end else showmessage('Instances control not allowed'); end;
procedure CheckDate;
This procedure gets the current date from an internet server and compares it with the system date. If there is a difference greater than one day brings up a dialog inviting the user to correct the system date from the Internet.
procedure CheckDate; var onlinedate:tdatetime; dif:integer; begin onlinedate := GetOnlineDate(AVLock.TimeHost); dif := trunc(abs(date - onlinedate)); if (dif > 1) then begin if (messagedlg('Your system date seems to be incorrect.'+#13#10+ 'Computer date = '+formatdatetime('mmm dd, yyyy',date)+#13#10+ ' Online date = '+formatdatetime('mmm dd, yyyy',onlinedate)+#13#10+ 'Would you like to fix your system date now? ', mtConfirmation, [mbYes, mbNo], 0) = mrYes) then fixsystemdate(onlinedate); end else showmessage('Your system date seems to be correct'); end;
procedure CheckAndFixDate;
This procedure verifies that the application is registered and then corrects the system date using OnlineChackDate.
procedure CheckAndFixDate; begin if (keydata.Status = registered) then AVLock.OnlineCheckDate(true) //fix system date else showmessage('Please register or start the trial period before to call this feature.'); end;
function RemoveReg(var newstatus:string):string;
This function removes the registration data from the OLM and locally. Will allow you to remove the existing registration in order to retest with another configuration. It should not be accessible to end users.
function RemoveReg(var newstatus:string):string; var ok:boolean; s:string; begin if AVLock.EraseReg then result:= 'Local registration data removed'+#13#10 else result:= 'Could not remove Local registration data'+#13#10; ok:=False; s:= AVLock.OnlineRemoveReg(0); //remove regitration data from the Advanced OLM ok:= ((s='00') or (s='11')); if ok then result:=result+'Online registration data removed' else result:=result+'Could not remove Online registration data'; newstatus:=GetRegStatus; end;
|