9. Licensing your application
Fnd_Reg lets your application run as a time-limited demo and unlock with a code you issue. It licenses your application; Foundation itself has no licence enforcement and never did since version 6. Fnd_RegG is the other half, the code generator, which you run in your own customer database.
Keep the limits in mind before you build on it: the codes are MD5-based and the generator ships in Foundation's source, so the scheme deters casual copying and nothing more. Its strength is your secret key, which never leaves your code.
The table
Fnd_Reg keeps its state in a [Fnd_Reg] table in your structure:
| Field | Type |
|---|---|
ID | Longint, indexed |
Feature_Code | Alpha 80, indexed |
Demo_Days | Integer |
Demo_Start_Date | Date |
Unlock_Code | Alpha 40 |
User_Name | Alpha 80 |
License_Info | Alpha 80 |
Checksum | Alpha 40 |
The first Fnd_Reg call of a session checks for it. In an interpreted host Foundation offers to create it and asks you to restart; compiled, it reports and Fnd_Reg stays inactive, with no alert and no abort. Because the demo start date and the unlock code are records, a new data file starts a new demo.
Quick start
In Fnd_Hook_Shell_Startup, or anywhere that runs once after Fnd_Shell_OnStartup:
Fnd_Reg_SetSecretKey("a phrase nobody will guess")
Fnd_Reg_DemoDays(""; 30)
Fnd_Reg_BuyNowURL(""; "https://www.example.com/buy")
Fnd_Reg_DemoDialog
Fnd_Reg_SetSecretKeymust come before any otherFnd_Regcall; there is no getter.Fnd_Reg_DemoDayssets the trial length for a feature code; the empty code is the application as a whole. It does not move an expiry already set.Fnd_Reg_DemoDialogshows the demo dialog unless the feature is registered: days remaining, Buy Now, Register, Continue.Fnd_Reg_StartDemoPeriodbegins the clock. Call it at launch, or at the first real use (the first record saved); it does nothing the second time.
Then ask the state wherever a feature is gated:
Case of
: (Fnd_Reg_RegistrationState=Fnd_Reg_Registered)
// full function
: (Fnd_Reg_RegistrationState=Fnd_Reg_Demo)
// trial, days remaining in Fnd_Reg_GetDemoDaysRemaining
: (Fnd_Reg_RegistrationState=Fnd_Reg_Expired)
Fnd_Reg_DemoDialog
: (Fnd_Reg_RegistrationState=Fnd_Reg_PreDemo)
// never started
End case
Issuing a code
In your customer database, with the same secret key:
$code_t:=Fnd_RegG_GenerateUnlockCode("a phrase nobody will guess"; ""; [Customer]Company)
The customer enters that code and the same name in the Registration dialog (Fnd_Reg_RegistrationDialog), or your code calls Fnd_Reg_Register(featureCode; unlockCode; userName), which sets OK to 1 on success. The optional fourth argument of the generator, licence information (a seat count, an edition), is bound into the code and readable afterwards with Fnd_Reg_GetLicenseInfo.
Feature codes
Every Fnd_Reg call takes an optional feature code, so one application can license several features separately, each with its own demo period, message and Buy Now URL: Fnd_Reg_FeatureName("REPORTS"; "Reporting module"), Fnd_Reg_DemoMessage("REPORTS"; "…"). The empty code is the application.
Dialogs
The demo and registration dialogs are Foundation's, localised through Fnd_Loc, and show your DatabaseName. Fnd_Reg_Reset(featureCode) clears a feature's registration and demo start for testing.
Testing
The module was exercised before release with a 127-assertion test of every call that opens no dialog. The one fact from it a host needs: the [Fnd_Reg] table must exist when 4D starts, so a table created by Fnd_Reg_CreateTable needs a restart before the first real run.