This article will give step-by-step instructions on how to add software licensing (specifically, hardware-locked or node-locked licensing) to your Xojo app. There's also a full example app that you can download and play with without needing to add licensing to your app.
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.
Before you can do anything, you need to login to your LimeLM account (or sign up). Then download TurboActivate for Windows, macOS (Mac OS X), or Linux. It contains the native library and source code examples needed to integrate hardware-locked licensing in your Xojo 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 Xojo app. There are lots of ways you can add licensing to your app, but there are 2 popular styles:
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.
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.
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, inside the extracted folder you'll find 2 folders: the "
API" directory and the "
bin-*" directory (for example,
bin-windows, for the Windows TurboActivate package).
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.
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).
You'll be copying this TurboActivate.dat files in the next step to sit alongside your executable files in each of the platforms you want to support.
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).
Included in TurboActivate API packs (get them on the API page) is a simple Xojo (Real Basic) example project. We've also included all the files you need to add to your Xojo project within the "Import to your project" folder. Just drag all of the files in that folder into your Xojo "Project" tab (or add the files one-by-one using the "File -> Import..." menu). The TurboActivate module contains all the functions you'll be using to add licensing, online-activation, and trial functionality to your app.
On Windows you'll be using the x86 version of TurboActivate. Copy the TurboActivate.dll to the same folder as the example project (and your project). And while you're at it put the TurboActivate.dat file that you downloaded earlier in this same folder. Now you can use TurboActivate while debugging your app. If you're not outputting your final exe to the same folder as your Xojo project then make sure to include the TurboActivate.dll and TurboActivate.dat files in the same folder as your outputted *.exe file.
macOS is a bit different than Windows. On Windows, when you build your app, you have a single exe and all you have to do is include the TurboActivate.dat and TurboActivate.dll files in the same folder as that exe. On macOS, however, when you build your app a "bundle" is created. If you're not familiar with macOS an "app bundle" is like an exe (you double click it and your app runs), however behind the scenes the "bundle" is just a folder with the actual app and resources in sub-folders.
For instance, when you use our example Xojo project and build on Mac a "TestApp" bundle will be output:
This is really a folder called "TestApp.app". When you're releasing your app for customers you'll want the TurboActivate.dat and libTurboActivate.dylib files to be inside the app bundle. You can do this manually by right clicking the app bundle (in the example, TestApp) then clicking "Show Package Contents":
Add the TurboActivate.dat file to the
TestApp.app/Contents/MacOS/ folder and add the libTurboActivate.dylib file to the
If you actually want to use TurboActivate while you're debugging your app then you need to make a temporary change to the "TALibrary" constant in the TurboActivate module:
For instance, to use the libTurboActivate.dylib in the same folder as your app's bundle, then change the "Mac OS" value to the following:
You'll also need to call PDetsFromPath() to load the TurboActivate.dat. For example, put this before you make any TurboActivate function calls:
#If DebugBuild ta = new TurboActivate("Paste GUID Here", "/location/to/TurboActivate.dat") #else ta = new TurboActivate("Paste GUID Here") #Endif
A good place to put these lines of code is before your call to IsGenuine() or IsActivated().
Now, inside your app, you need to create a new TurboActivate object with the Version GUID found on the same page you downloaded the TurboActivate.dat from. In the example app we create the "TurboActivate" object with your version GUID like so:
' TODO: goto the version page at LimeLM and paste this GUID here ta = new TurboActivate("Paste GUID Here")
Replace the "Paste GUID Here" string with the Version GUID string your copied from your version page.
There are many ways you can use TurboActivate to add licensing to your application. For this example we're going to keep it simple.
The the example we're creating a simple variable "
isGenuine" to save whether the customer is activated and genuine. And then it's simply a matter of making a call to
IsGenuine(X, Y, Z) 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:
Try 'TODO: goto the version page at LimeLM and paste this GUID here #If DebugBuild ta = new TurboActivate("Paste GUID Here", "/location/to/TurboActivate.dat") #else ta = new TurboActivate("Paste GUID Here") #Endif ' 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/ Dim gr As IsGenuineResult = ta.IsGenuine(DaysBetweenChecks, GracePeriodLength, True) isGenuine = (gr = IsGenuineResult.Genuine Or _ gr = IsGenuineResult.GenuineFeaturesChanged Or _ gr = IsGenuineResult.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 ' 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. Dim frmReverify as new ReVerifyNow(ta, DaysBetweenChecks, GracePeriodLength) frmReverify.ShowModal() If frmReverify.OKClicked Then isGenuine = True ElseIf Not frmReverify.noLongerActivated Then ' the user clicked cancel and the user is still activated ' Just bail out of your app Quit Exit Sub End If End If Catch err As TurboActivateException MsgBox "Failed to check if activated: " + err.Message ' End your application immediately Quit End Try
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:
It creates the new TurboActivate instance with your Version GUID.
Checks if the customer is activated and re-verifies with the servers every 90 days (with a 14-day grace period).
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.
And if it's a case where the customer must re-verify with the activation servers, then prompt them to do that (also included in the example project).
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 a simple form ("PKey") 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. Now we need to handle when the user clicks the Activate/Deactivate menu that you created. You can add code to Deactivate if the user is activated, or launch the "PKey" form if the user isn't activated:
Try If isGenuine Then ' deactivate product without deleting the product key ' allows the user to easily reactivate ta.Deactivate(False) isGenuine = False ShowTrial(True) Else ' use a simple activation interface Dim pkeyDialog as new PKey(ta) pkeyDialog.ShowModal() ' recheck if activated isGenuine = ta.IsActivated() If isGenuine Then ReEnableAppFeatures() ShowTrial(False) End If End If Catch err As TurboActivateException MsgBox "Failed to activate: " + err.Message Return False End Try Return True
In the included example app, the
PKey window calls
ta.CheckAndSavePKey(txtPKey.Text, TA_SYSTEM) when the "Activate" button is clicked. The
TA_SYSTEM flag tells TurboActivate to store the activation data to directories where all users on that machine would have the ability to read/write the activation data. If you were using
TA_USER instead, this would tell TurboActivate to store the activation data in directories that the user has the ability to write to.
In both cases the activation data locks to the machine. The only difference is where the activation data is stored. We typically recommend using
TA_SYSTEM, however the only downside to using that flag is that the first time (and only the first time) you call a function with the
TA_SYSTEM flag your app needs "elevated" or "sudo" permission.
In this example we're going to use verified trials because they are accurate, fast, and allows you to track conversion of customers. Starting the verified trial and seeing how many days are remaining is as simple as this:
' 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 lblTrialMessage.Visible = show btnExtendTrial.Visible = show If show Then mnuActDeact.Text = "Activate..." Dim trialDaysRemain As Integer = 0 Try ta.UseTrial(trialFlags) ' get the number of remaining trial days trialDaysRemain = ta.TrialDaysRemaining(trialFlags) Catch tee As TrialExpiredException ' do nothing because trialDaysRemaining is already set to 0 Catch ex As TurboActivateException MsgBox "Failed to start the trial: " + ex.Message End Try ' if no more trial days then disable all app features If trialDaysRemain = 0 Then DisableAppFeatures() Else lblTrialMessage.Text = "Your trial expires in " + Str(trialDaysRemain) + " days." End If Else mnuActDeact.Text = "Deactivate" End If