LimeLM
wyBuild
Support forum
wyDay blog
wyDay Home

Using TurboActivate with Delphi

DelphiThis article will give step-by-step instructions on how to add software licensing (specifically, hardware-locked or node-locked licensing) to your Delphi app. There's also a full example app (one Delphi VCL example and one Delphi FireMonkey example) that you can download and play with without needing to add licensing to your app. The examples apps, and this article, support Delphi 7 and newer.

By the end of this article you'll have working licensing integrated with your application, and thus the ability to sell individual copies of your software.

Sign up or login and download the native TurboActivate library

Before you can do anything, you need to login to your LimeLM account (or sign up). Then download TurboActivate for Windows or macOS (Mac OS X). It contains the native library and source code examples needed to integrate hardware-locked licensing in your app:

Step-by-step walkthrough: adding licensing and trials to your Delphi app

Now we're going to walk you through each step you need to take in adding licensing, online activation, and timed-trials to your Delphi app. There are lots of ways you can add licensing to your app, but there are 2 popular styles:

  1. Separate versions of your app. This style of licensing is where you build 2 versions of your product: a trial version and a full version.

  2. Hybrid version of your app. This style of licensing is where your product is the trial version or the full version depending on whether the user is activated.

The first method (the separate versions method) is possible with TurboActivate, but we're not going to talk about it here because it's not very user friendly and it requires more work on your end. Instead we'll talk about making your app a hybrid Full/Trial app. That is, your users will be able to use your app in "trial mode" until either the trial expires or they purchase a product key and use it to activate your app.

Step 1. Signup for LimeLM, download TurboActivate

If you haven't already signed up for LimeLM then sign up now. All plans have a 30-day free trial. Or, if you're just putting your toes in the water, there's even a free plan that has no time limit and doesn't require a credit card.

After you've created your account, download TurboActivate and extract it anywhere. After you extract it you'll find 4 folders:

Step 2. Add TurboActivate to your project

Now you need to add TurboActivate to your app. Add "TurboActivateUnit.pas" from the "Delphi" project you extracted from the TurboActivate main package. You do this by right clicking your project in Delphi and clicking "Add..." and browsing for the "TurboActivateUnit.pas" file:

Adding existing files to Delphi

Next we'll copy "TurboActivate.exe" and "TurboActivate.dll" from the x86 folder we extracted. Put these files in both your project's "Debug" and "Release" folders.

Step 3. Create a new product in LimeLM

If you haven't already created a new product in LimeLM, do it now. You can change any value later, so don't worry about making a mistake.

Adding your first product to LimeLM

Step 4. Download TurboActivate.dat

Go to your version page in LimeLM. Download the "TurboActivate.dat" file, and make a note of the Version GUID you see on your product version page (you'll be using it in the next step).

TurboActivate.dat and Version GUID

Copy the TurboActivate.dat file you just downloaded to your app's "Release" and "Debug" folders. When you distribute your app to your customers you'll be including this TurboActivate.dat alongside your binary.

Side-note about TurboActivate.dat file: this file is an "information file" about your product version, and gives TurboActivate enough information to verify product keys and cryptographically signed activation data locally. It's a read-only file (license data will never be written to it).

Step 5 (optional). Prepare for macOS (Mac OS X) debugging & deployment

If you're using Delphi FireMonkey, and you want to target macOS, then you need to configure your project to include the libTurboActivate.dylib and TurboActivate.dat files in your app bundle. If you haven't done it already, download TurboActivate for macOS (Mac OS X), and extract it. Inside you'll find the libTurboActivate.dylib file you'll be using later in this step.

In your Delphi FireMonkey project, click the "Project" menu, then click the "Deployment" menu item. It will open a new tab in the project as shown below:

Deploy for macOS

In that "Deployment" tab, do the following:

  1. In the deployment platform drop-down, choose "All configuration - OS X platform"

  2. Click the green "Add files" button.

  3. Find the libTurboActivate.dylib and TurboActivate.dat files and add them both. (Make sure that they're added to both the "Debug" and "Release" configurations.

  4. Change the "Remote Path" for libTurboActivate.dylib and TurboActivate.dat to Contents\MacOS\ so that those 2 files will be sitting next to the actual executable inside the macOS ".app" bundle.

After doing all those steps you can now debug and release your app on macOS.

Step 6. Fix Delphi's exception settings

Delphi XE (released 2011) and all newer versions are mis-configured by default. In Delphi, you need to go to "Tools" menu, click "Options", and scroll down to the "Debugger Options -> Embarcadero Debuggers -> Native OS Exceptions" and change 2 settings. First, under the "32-bit Windows OS Exceptions", change the "Privileged Instruction" to be handled by "User program". Next, under the "64-bit Windows OS Exceptions", again, change the "Privileged Instruction" to be handled by "User program":

Fixing Delphi's misconfiguration of Privileged Instructions

If you don't do this, then when you run your app under the debugger you'll get exceptions that will crash your app. Why? Because the way TurboActivate works is that it throws exceptions and then catches them internally. However, with Delphi's default value of the "Debugger" handling the "Privileged Instruction", the Delphi debugger interrupts TurboActivate's default behavior with no real benefit other than to annoy and confuse you. This is a poor design choice on Embarcadero's part.

Step 7. Creating the TurboActivate instance

In the example "Text Editor" Delphi application the "frmMain.pas" file is the main UI for the app. That is, it's the entry point for the application. And because it's the entry point of the application it's where we'll be checking the activation.

First, create the TurboActivate instance as a private member in the class:

var
  Form1: TForm1;
  ta: TurboActivate;

Then, in the constructor for the form, you'll actually create the new instance of the TurboFloat class. Paste the Version GUID you copied from earlier:

procedure TForm1.FormCreate(Sender: TObject);
begin
   Try
       //TODO: goto the version page at LimeLM and paste this GUID here
       ta := TurboActivate.Create('PASTE-VERSION-GUID-HERE');
   except

     on Ex : ETurboActivateException do
     begin
         ShowMessage('Failed to check if activated: ' + E.Message);

         // Exit the app, and exit the function immediately
         Application.Terminate;
         exit;
     end;
   end;

// ...

Step 8. Checking if the customer is genuinely activated

There are many ways you can use TurboActivate to add licensing to your application. For this example we're going to keep it simple.

Scroll up to the "var" section of your main form and add a "Boolean" "isGenuine" variable to save whether the customer is activated and genuine.

var
  Form1: TForm1;
  ta : TurboActivate;
  trialFlags: LongWord;
  DaysBetweenChecks: LongWord;
  GracePeriodLength: LongWord;

And then it's simply a matter of making a call to IsGenuine() to see if the user is activated and to re-verify the activation with the LimeLM servers every 90 days, with a 14 day grace period:

procedure TForm1.FormCreate(Sender: TObject);
var
  gr : IsGenuineResult;
  frmReverify : TfrmReVerifyNow;
begin

   // Don't use 0 for either of these values.
   // We recommend 90, 14. But if you want to lower the values
   // we don't recommend going below 7 days for each value.
   // Anything lower and you're just punishing legit users.
   DaysBetweenChecks := 90;
   GracePeriodLength := 14;


   Try
       //TODO: goto the version page at LimeLM and paste this GUID here
       ta := TurboActivate.Create('Paste GUID Here');

       // Check if we're activated, and every 90 days verify it with the activation servers
       // In this example we won't show an error if the activation was done offline
       // (see the 3rd parameter of the IsGenuine() function) -- https://wyday.com/limelm/help/offline-activation/
       gr := ta.IsGenuine(DaysBetweenChecks, GracePeriodLength, true);

       isGenuine := (gr = Genuine)
                     or (gr = GenuineFeaturesChanged)

                     // an internet error means the user is activated but
                     // TurboActivate failed to contact the LimeLM servers
                     or (gr = InternetError);


       // If IsGenuineEx() is telling us we're not activated
       // but the IsActivated() function is telling us that the activation
       // data on the computer is valid (i.e. the crypto-signed-fingerprint matches the computer)
       // then that means that the customer has passed the grace period and they must re-verify
       // with the servers to continue to use your app.

       //Note: DO NOT allow the customer to just continue to use your app indefinitely with absolutely
       //      no reverification with the servers. If you want to do that then don't use IsGenuine() or
       //      IsGenuineEx() at all -- just use IsActivated().
       if (not isGenuine) And ta.IsActivated then
       begin
           // We're treating the customer as is if they aren't activated, so they can't use your app.

           // However, we show them a dialog where they can reverify with the servers immediately.
           frmReverify := TfrmReVerifyNow.Create(nil, ta, DaysBetweenChecks, GracePeriodLength);

           if frmReverify.ShowModal = mrOk then begin
              isGenuine := true;
           end
           else if (not frmReverify.noLongerActivated) then begin // the user clicked cancel and the user is still activated
              // Just bail out of your app
              Application.Terminate;
              exit;
           end;
       end;
   except
     on E : ETurboActivateException do
     begin
       ShowMessage('Failed to check if activated: ' + E.Message);

       // Exit the app, and exit the function immediately
       Application.Terminate;
       exit;
     end;
   end;

   // Show a trial if we're not genuine
   // See step 9, below.
   ShowTrial(not isGenuine);
end;

This is a complete example showing how to check if the customer is genuinely activated, and how to handle the error cases. While it's longer than "toy" licensing solutions, it's built for the real world.

The code does the following:

  1. It creates the new TurboActivate instance with your Version GUID.

  2. Checks if the customer is activated and re-verifies with the servers every 90 days (with a 14-day grace period).

  3. And if IsGenuine(x, y, z) tells you the customer is not genuine then you can use IsActivated() to determine if they're "not genuine" because they were never activated or if it's because the customer has gone more than DaysBetweenChecks + GracePeriodLength days since re-verifying with the activation servers.

  4. And if it's a case where the customer must re-verify with the activation servers, then show a form that lets them do that (also included in the example project).

Step 9. Prompting for the user's product key

If the user has never activated, or if they've since deactivated, then you'll need to prompt the user to enter their product key. You can do this a couple of ways, in this example we'll just use the TurboActivate Wizard to prompt the customer to enter their product key.

The first thing you need to do is a new Activate/Deactivate menu to your form. You can name it anything you want — in this example we call it mnuActDeact:

Add Activate/Deactivate menu to your app

After you've created the menu item, changed the name to mnuActDeact in the properties window, click the "Events" tab, then double click the "OnClick" event and Delphi will automatically generate the event code for you:

Activate menu click event

Now we need to handle when the user clicks the Activate/Deactivate menu that you created. Scroll down to the "mnuActDeact_Click" function that Delphi generated for you. You can add code to Deactivate if the user is activated, or launch TurboActivate.exe if the user isn't activated:

procedure TForm1.mnuActDeactClick(Sender: TObject);
var
  StartInfo : TStartupInfo;
  ProcInfo : TProcessInformation;
  CreateOK : Boolean;
  TurboActivateExe: string;
begin

  if isGenuine then
  begin
    // deactivate product without deleting the product key
    // allows the user to easily reactivate
    ta.Deactivate(false);
    isGenuine := false;
    ShowTrial(True);
  end
  else // this app isn't activated - launch TurboActivate and wait for it to exit
  begin
    //Note: you can launch the TurboActivate wizard or you can create you own interface

    ZeroMemory(@StartInfo, sizeOf(TStartUpInfo));
    ZeroMemory(@ProcInfo, sizeOf(TProcessInformation));

    StartInfo.cb := SizeOf(TStartupInfo);

    TurboActivateExe := 'TurboActivate.exe';

    // make the reference count of the string at least 1 necessary for Delphi 2009 +
    UniqueString(TurboActivateExe);

    // launch TurboActivate
    CreateOK := CreateProcess(nil, PChar(TurboActivateExe), nil, nil,False,
                NORMAL_PRIORITY_CLASS,
                nil, nil, StartInfo, ProcInfo);

    if CreateOK then
      begin
        // if you don't want your main window to lockup, then wait on a separate thread
        WaitForSingleObject(ProcInfo.hProcess, INFINITE);

        // recheck if activated
        if ta.IsActivated() then
        begin
            ShowActivateMessage(false);
            mnuActDeact.Caption := 'Deactivate';
            isGenuine := true;
        end;
      end
    else ShowMessage('Unable to run TurboActivate.exe');

    CloseHandle(ProcInfo.hProcess);
    CloseHandle(ProcInfo.hThread);
  end;
end;

Step 10. Adding trial functionality

In other parts of this example you've seen references to a ShowTrial() function. This is a function that you'll need to create to add trial functionality to your app. In this example we're going to use verified trials (because they are accurate, fast, and allows you to track conversion of customers).

The first step is to actually tell TurboActivate you'll be using verified trials. Create a trialFlags at the top of your main form that will store this information:

procedure TForm1.FormCreate(Sender: TObject);
var
  gr : IsGenuineResult;
  frmReverify : TfrmReVerifyNow;
begin

   // Set the trial flags you want to use. Here we've selected that the
   // trial data should be stored system-wide (TA_SYSTEM) and that we should
   // use un-resetable verified trials (TA_VERIFIED_TRIAL).
   trialFlags := TA_SYSTEM or TA_VERIFIED_TRIAL;

   // Don't use 0 for either of these values.
   // We recommend 90, 14. But if you want to lower the values
   // we don't recommend going below 7 days for each value.
   // Anything lower and you're just punishing legit users.
   DaysBetweenChecks := 90;
   GracePeriodLength := 14;

Now we have to make a few functions:

  1. ShowTrial(bool show)

  2. DisableAppFeatures()

  3. ReEnableAppFeatures()

In the ShowTrial method you can show how many trial days remain for the user. You can open the Delphi example from TurboActivate.zip if you want to see a full example. Here we'll set the activate menu text to either "Activate" or "Deactivate" and will disable the app features if there are no more trial days remaining:

procedure TForm1.ShowTrial(show: boolean);
var
  trialDaysRemaining : LongWord;
begin
  lblTrialMessage.Visible := show;
  btnExtendTrial.Visible := show;

  if show then
  begin
    mnuActDeact.Caption := 'Activate';

    trialDaysRemaining := 0;
    Try
        ta.UseTrial(trialFlags);

        // get the number of remaining trial days
        trialDaysRemaining := ta.TrialDaysRemaining(trialFlags);
    except
     on E : ETurboActivateException do
     begin
       ShowMessage('Failed to start the trial: ' + E.Message);
     end;
    end;

    // if no more trial days then disable all app features
    if trialDaysRemaining = 0 then
       DisableAppFeatures()
    else
       lblTrialMessage.Caption := 'Your trial expires in ' + IntToStr(trialDaysRemaining) + ' days.';
  end
  else
    mnuActDeact.Caption := 'Deactivate'
end;

Now you can add the functions to your code to disable and enable your application features:

procedure TForm1.DisableAppFeatures();
begin
  //TODO: disable all the features of the program
end;

procedure TForm1.ReEnableAppFeatures();
begin
  //TODO: re-enable all the features of the program
end;

In the example Delphi project the app "feature" we enable/disable is the text box. Obviously you need to tailor this to your specific application.

Now that we have the foundation set we can actually start calling these functions. Scroll back up to the form's constructor and add the call to the ShowTrial() function:

procedure TForm1.FormCreate(Sender: TObject);
begin

   Try
       ta := TurboActivate.Create('Paste GUID Here');

       // ... IsGenuine() code from above goes here
   except
     on E : ETurboActivateException do
     begin
       // Handle exception
     end;
   end;

   ShowTrial(not isGenuine);
end;