This article will give step-by-step instructions on how to add floating-licensing to your C, C++, or Objective-C 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 floating-licensing integrated with your application, and thus the ability to sell individual copies of your software.
This article shows you how to add floating-licensing to your C or C++ app using TurboFloat. To add hardware-locked licensing to your app see the "Using TurboActivate with C, C++, and Objective-C " article.
Before you can do anything, you need to login to your LimeLM account (or sign up). Then download TurboFloat for Windows, macOS, Linux, or BSD. It contains the native library and source code examples needed to integrate floating-licensing in your C or C++ app:
After you've created a new product, go to the version page of the product you will be adding licensing to. You will need to do 2 things:
You'll be including the TurboActivate.dat file in the same folder as the TurboFloat.dll file and you'll use the Version GUID in your code as part of integrating TurboFloat within your app.
Included in TurboFloat Library package is a simple example project. The TurboFloat.h header file contains all the functions you'll be using to add the floating licenses functionality to your app. Also, if you're targeting Windows, you need link against the "TurboFloat.lib" file.
#include "TurboFloat.h"
#ifdef _WIN32
#pragma comment (lib, "TurboFloat.lib")
#endif
We're going to walk you through adding floating licensing to your app by using our C example application. If you haven't downloaded it already you can get the example app inside the TurboFloat Library package.
Before you can continue, you need to start a TurboFloat Server instance. We recommend spinning-up a TurboFloat Server instance on our infrastructure using LicenseChest. Alternatively, your customers can host the TurboFloat Server on their own infrastructure by activating and installing the TurboFloat Server locally.
We recommend using our hosted TurboFloat Server option because it's fast, stable, up-to-date, and incredibly easy to deploy.
In the example console C application you'll see the first things we do, besides including "TurboFloat.h", is creating a public variable that will contain the "handle" you'll be using in the TurboFloat functions:
#include "TurboFloat.h"
uint32_t tfHandle;
Then you get the "handle" by calling the TF_GetHandle()
function:
int main(int argc, char* argv[])
{
/* Get the handle that will be used for TurboFloat function
calls.
TODO: paste your Version GUID here.
*/
tfHandle = TF_GetHandle(_T("PASTE-VERSION-GUID-HERE"));
Note: if your TurboActivate.dat file isn't in the same path as your executable, then you need to tell TurboFloat to load the TurboActivate.dat file before you can get the handle. You do that by calling the TF_PDetsFromPath()
function before calling TF_GetHandle()
:
int main(int argc, char* argv[])
{
/* Used to store TurboFloat responses. */
HRESULT hr;
hr = TF_PDetsFromPath(L"C:\\Path\\To\\TurboActivate.dat");
if (hr != TF_OK)
{
printf("Failed to load the TurboActivate.dat file. ");
printf("TF_PDetsFromPath() returned %d. Look in TurboFloat.h for a human readable explanation of the error.\n", hr);
return 1;
}
tfHandle = TF_GetHandle(_T("PASTE-VERSION-GUID-HERE"));
The TurboFloat library handles all the details about renewing leases, retrying, etc. All you have to do is handle the cases where TurboFloat talks to your app and tells it something has changed (license lease failing to be renewed or new license field data). To do this you need to create a function to handle these callbacks from TurboFloat:
void TF_CC LeaseCallback(uint32_t status)
{
switch (status)
{
case TF_CB_FEATURES_CHANGED:
//TODO: reload any features using TF_GetFeatureValue().
printf("TODO: reload any features using TF_GetFeatureValue()\n");
PrintLicenseField();
break;
case TF_CB_LEASE_DROPPED_SLEEP:
printf("The lease has been dropped due to computer sleeping.\n");
/* TODO: prompt the user to re-connected -- hide this prompt upon receipt of TF_CB_LEASE_REGAINED */
break;
case TF_CB_LEASE_REGAINED:
printf("The lease has been successfully regained after a sleep.\n");
/* TODO: hide a prompt to the user if shown during TF_CB_LEASE_DROPPED_SLEEP */
break;
// explicitly handle errors
// also, handle unknown statuses ("default")
// as errors.
case TF_CB_EXPIRED:
case TF_CB_EXPIRED_INET:
case TF_CB_LEASE_DROPPED:
default:
//TODO: disable any features in your app.
printf("The lease expired or has been dropped.\n");
/*
After disabling the user's access to your app, we recommend
you do 3 things:
1. Give the user the option to save their progress.
2. Give the user the option to save their progress to a
separate file (i.e. "Save as" in case the work they were
doing was incomplete).
3. Give the user the option to retry. For example a
"Try again" button that calls TF_RequestLease(tfHandle).
*/
// Don't just exit the app without warning or without
// giving the user options. For example, this behavior
// right here is a terrible example to be setting:
printf("The app is exiting. In your app you shouldn't just abruptly exit! That's bad. See the comments in the example app.\n");
exit(1);
break;
}
}
Also, make note of the TF_CC
before the function name:
void TF_CC LeaseCallback(uint32_t status){ ...
This tells your compiler to use the "cdecl" calling convention on Windows. This is required by TurboFloat. On other platforms (Linux, Mac OS X, etc.) it doesn't do anything — you can just leave the TF_CC
declaration in there an the compiler will ignore it.
Next, we need to tell TurboFloat about the callback function:
tfHandle = TF_GetHandle(_T("PASTE-VERSION-GUID-HERE"));
/*
Set the function that TurboFloat will call from
another thread letting your app know about changes
to the floating license.
*/
hr = TF_SetLeaseCallback(tfHandle, LeaseCallback);
Now it's simply a matter of requesting the lease from the TurboFloat Server using the TF_RequestLease()
function:
tfHandle = TF_GetHandle(_T("PASTE-VERSION-GUID-HERE"));
hr = TF_SetLeaseCallback(tfHandle, LeaseCallback);
hr = TF_RequestLease(tfHandle);
if (hr == TF_E_SERVER)
{
/*
We're just hardcoding the localhost for testing
purposes in real life you'd want to let the user
enter the host address / port you can either do
this in your app, or in your installer.
If your customer is using LicenseChest hosted TFS
instances, you might want to make a simple prompt
for the LicenseChest TFS UUID.
More information: https://wyday.com/licensechest/help/create-tfs-instance/
Then call TF_SaveServer(...) using
"floating.wyday.com/?server=[UUID]" as the host address.
For example:
hr = TF_SaveServer(tfHandle, _T("floating.wyday.com/?server=00000000-0000-0000-0000-000000000000"), 443, TF_USER | TF_REQUEST_OVER_HTTPS);
*/
hr = TF_SaveServer(tfHandle, _T("127.0.0.1"), 13, TF_SYSTEM);
if (hr != TF_OK)
{
printf("Failed to save the sever details (TF_SaveServer() returned %d). Look in TurboFloat.h for a human readable explanation of the error.\n", hr);
return 1;
}
/* try to get a lease again */
hr = TF_RequestLease(tfHandle);
}
else if (hr == TF_E_INET
|| hr == TF_E_INET_TIMEOUT
|| hr == TF_E_WRONG_SERVER_PRODUCT
|| hr == TF_E_SERVER_UUID_MISMATCH
|| hr == TF_E_USERNAME_NOT_ALLOWED)
{
/*
Give the user an option to try another server if they
couldn't connect to the first one, or if the first one
is for a different product.
*/
}
// If the lease wasn't acquired then output an error and exit.
// You can view all the error codes in TurboFloat.h near the bottom of the file.
if (hr != TF_OK)
{
printf("Failed to get the floating license lease (TF_RequestLease() returned %d). Look in TurboFloat.h for a human readable explanation of the error.\n", hr);
return 1;
}
Also notice how we're handling the case where the end-user hasn't already specified the floating license server (the TF_E_SERVER
error). Instead of just hardcoding the server and port (like we show in the example), you should prompt the user to enter the details. Then you can call the TF_SaveServer()
function to save the details.
You should also give your customers the ability to easily choose using TFS instances hosted on our infrastructure using LicenseChest by simply prompting them to enter the server UUID (a small string that uniquely identifies their TFS instance). Then it's simply a matter of calling TF_SaveServer()
and appending the user-entered UUID to the hosted TFS address like so:
hr = TF_SaveServer(tfHandle, _T("floating.wyday.com/?server=UUID_HERE"), 443, TF_USER | TF_REQUEST_OVER_HTTPS);
After you've successfully requested a lease from the TurboFloat Server, the TurboFloat library integrated in your app takes care of renewing the leases automatically and silently. You'll only ever get a notification of something going wrong in the callback function that we covered in Step 3.
When your app is closing you should "drop" the lease using the TF_DropLease()
function, and cleanup the memory using the TF_Cleanup()
function::
/* Drop the floating license, wait for the response,
then exit your app.
*/
if (TF_HasLease(tfHandle) == TF_OK)
hr = TF_DropLease(tfHandle);
/* Output the error if there is one.
Look in TurboFloat.h for what the error codes mean.
*/
if (hr != TF_OK)
printf("Dropping the lease failed: (%d), exiting anyway.\n", hr);
/* Cleanup the memory. */
hr = TF_Cleanup();
What this does is tell the TurboFloat Server that you're through using the lease in this instance of your app, and another instance of your app on another computer or another session can now use that "free slot".
If you can't drop the lease (because your app can't connect to the internet, or for any other reason), and you choose to exit your app anyway, then the "lease" on the TurboFloat Server will be a "zombie". The lease will expire eventually on the TurboFloat Server, and thus the free slot will open back up.
Testing requesting leases, dropping them, and everything else in the TurboFloat Library is intuitive: just call the function and it does the thing you want it to do. Testing the lease callback function is, however, slightly less intuitive. Here's how you can test the callback function:
If your app is open and has a lease, close your app and make sure it drops the license lease from the TurboFloat Server.
Stop the TurboFloat Server instance.
Open the TurboFloat Server config file, and edit <lease .../>
element and set it to "30". This will set the lease length to 30 seconds.
Save the changes you made to the configuration file.
Start your TurboFloat Server instance again.
Start your app again, and make sure it successfully gets a license lease from the TurboFloat Server.
Now, stop the TurboFloat Server instance, but leave your app running.
Within the next 30 seconds the lease callback function will be called because the TurboFloat Library was not able to renew the license lease automatically.
You should also test the "TF_CB_LEASE_DROPPED_SLEEP
" and "TF_CB_LEASE_REGAINED
" callback types. These callbacks are raised when your app has a lease and the device your app is running on goes to sleep and then eventually wakes up. To test these scenarios:
Run a TurboFloat Server on a separate computer than the one you're running the test from (or spin up a TurboFloat Server instance on our infrastructure).
Start your app and acquire a lease from that TFS instance.
Put the computer which your app is running on to sleep.
After the computer has gone to sleep, wake it up.
Your app should handle both of those events seamlessly. Namely, prompting the user to reconnect when the computer goes to sleep, and if the lease is regained automatically, hiding that prompt from the user.