LimeLM
wyBuild
Support forum
wyDay blog
wyDay Home

Using TurboActivate with C, C++, and Objective-C

C/C++This article will give step-by-step instructions on how to add software licensing (specifically, hardware-locked or node-locked 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 licensing integrated with your application, and thus the ability to sell individual copies of your software.

This article shows you how to add hardware-locked licensing to your C or C++ app (using TurboActivate). To add floating-licensing to your C or C++ app see the "Using TurboFloat with C, C++, & Objective-C" article.

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, macOS, Linux, or BSD. It contains the native library and source code examples needed to integrate hardware-locked licensing in your app:

For more options, including static libraries, go to the API page.

Adding licensing & online activation to your appTurboActivate.dat and Version GUID

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:

  1. Download the TurboActivate.dat file for the product version.
  2. Make a note of the Version GUID.

You'll be including the TurboActivate.dat file in the same folder as the TurboActivate (.dll, .dylib, or .so) files and you'll use the Version GUID in your code as part of integrating TurboActivate within your app.

Using TurboActivate

In addition to the TurboActivate library and .dat file, there are 2 other files that you'll need to include with your app to use the TurboActivate API in C, C++, or Objective-C: TurboActivate.h and, if you're targeting Windows, the "TurboActivate.lib" file.

#include "TurboActivate.h"
#ifdef _WIN32
    #pragma comment (lib, "TurboActivate.lib")
#endif

If you're making a macOS or Linux app, you should also check out these articles:

TA_IsActivated(), TA_IsGenuine(), TA_IsGenuineEx()

There are 3 separate TurboActivate functions for checking whether a customer is activated or not:

For most cases we recommend using TA_IsGenuineEx(). For example:

GENUINE_OPTIONS opts = {0};
opts.nLength = sizeof(GENUINE_OPTIONS);

// How often to verify with the LimeLM servers (90 days)
opts.nDaysBetweenChecks = 90;

// The grace period if TurboActivate couldn't connect to the servers.
// after the grace period is over TA_IsGenuineEx() will return TA_FAIL instead of
// TA_E_INET or TA_E_INET_DELAYED
opts.nGraceDaysOnInetErr = 14;


// In this example we won't show an error if the activation
// was done offline by passing the TA_SKIP_OFFLINE flag
opts.flags = TA_SKIP_OFFLINE;


uint32_t taHandle = TA_GetHandle(YourProductVersionGUID);

if (taHandle == 0)
{
    printf("Failed to get the handle for the Version GUID specified. ");
    printf("Make sure the Version GUID is correct, and that TurboActivate.dat is in the same folder as your app.\n\n");
    printf("Or use TA_PDetsFromPath() to load the TurboActivate.dat first before getting the handle.\n");
    exit(1);
}

HRESULT hr = TA_IsGenuineEx(taHandle, &opts);

if (hr == TA_OK || hr == TA_E_FEATURES_CHANGED
   || hr == TA_E_INET || hr == TA_E_INET_DELAYED)
{
    // your app is activated and genuine

    if (hr == TA_E_INET || hr == TA_E_INET_DELAYED)
    {
        // TODO: show a warning to your customers that this time (or recently)
        // the IsGenuineEx() failed to connect to the LimeLM servers.
    }
}
else
{
    // TODO: Not activated OR not genuine OR activated but more than
    //       nDaysBetweenChecks + nGraceDaysOnInetErr has passed.
}

Handling the case where the customer has not re-verified with the server in X + Y days

If the customer has not successfully re-verified with the servers in nDaysBetweenChecks + nGraceDaysOnInetErr then TA_IsGenuineEx() will return TA_FAIL. So, how do you tell the difference between a customer that was never activated and a customer that is blocking your app from re-contacting the activation servers? You use the TA_IsActivated() function to see if there's a valid activation locally.

If TA_IsGenuineEx() returns TA_FAIL and TA_IsActivated() returns TA_OK then you know that the customer needs to reverify with the activation server before they can continue to use your app.

Here's one example of how to do that (as seen in the "Example.c" example console app):

// Check if the failure was a result of the customer not being activated
// OR if the failure was a result the customer not being able to re-verify with
// the activations servers.
if (TA_IsActivated(taHandle) == TA_OK)
{
    // There is still activation data on the computer, and it's valid.

    // This means that IsGenuineEx() is saying "not activated" (a.k.a. TA_FAIL)
    // because the customer blocked connections to the activation servers (intentionally or not)
    // for nDaysBetweenChecks + nGraceDaysOnInetErr days.

    // What you should do now is prompt the user telling them before they can use your app that they need
    // to reverify with the activation servers.

    char userResp = 0;

    printf("You must reverify with the activation servers before you can use this app. ");
    printf("Type R and then press enter to retry after you've ensured that you're connected to the internet. ");
    printf("Or to exit the app press X.\n");

    while ((userResp = getchar()) != 'X' && userResp != 'x')
    {
        if (userResp == 'R' || userResp == 'r')
        {
            // Now we're using TA_IsGenuine() to retry immediately. Note that we're not using
            // TA_IsGenuineEx() because TA_IsGenuineEx() waits 5 hours after an internet failure
            // before retrying to contact the servers. TA_IsGenuine() retries immediately.
            hr = TA_IsGenuine(taHandle);

            if (hr == TA_OK || hr == TA_E_FEATURES_CHANGED)
            {
                printf("Successfully reverified with the servers! You can now continue to use the app!\n");
                break;
            }
            else
            {
                printf("Failed to reverify with the servers.");
                printf("Make sure you're connected to the internet and that you're not blocking access to the activation servers.");
                printf("Then press R to retry again.: Error code = 0x%x\n", hr);

                //Note: actually show a human readable error code to the customer!
                // hr = 0xNN is not a useful error code. Look in TurboActivate.h for a
                // full list of error codes and what they mean.
            }
        }
        else
        {
            printf("Invalid input. Press R to try to reverify with the servers. Press X to exit the app.\n");
        }
    }

    // exit the app
    if (userResp == 'X' || userResp == 'x')
        exit(1);
}
else
{
    // The customer was never activated or deactivated (or got deactivated).
}

TA_UseTrial(), TA_TrialDaysRemaining()

The TA_UseTrial() function starts and/or re-validates the trial. The TA_TrialDaysRemaining() function gives you the number of days remaining in the trial. When TA_TrialDaysRemaining() returns 0 you should disable your apps features and require them to activate. See the example project.

Note: Always call TA_UseTrial() before calling TA_TrialDaysRemaining().

...

HRESULT hr = TA_IsGenuineEx(taHandle, &opts);

if (hr == TA_OK || hr == TA_E_FEATURES_CHANGED
   || hr == TA_E_INET || hr == TA_E_INET_DELAYED)
{
    // your app is activated and genuine

    ...
} 
else // not genuine / not activated
{
    // See if the customer needs to reverify with the servers
    if (TA_IsActivated(taHandle) == TA_OK)
    {
        //TODO: reverify with the servers
    }

    // 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).
    uint32_t trialFlags = TA_VERIFIED_TRIAL | TA_SYSTEM;

    // check if trial has expired
    uint32_t trialDays = 0;

    // Start or re-validate the trial if it has already started.
    // This need to be called at least once before you can use
    // any other trial functions.
    hr = TA_UseTrial(taHandle, trialFlags, NULL);

    if (hr == TA_OK)
    {
        // Get the number of trial days remaining.
        hr = TA_TrialDaysRemaining(taHandle, trialFlags, &trialDays);

        if (hr == TA_OK && trialDays > 0)
        {
            // trial days remaining
        }
        else
        {
            // trial has expired, disable the features of your app
            // tell the user they must activate
        }
    }
    else
        printf("TA_UseTrial failed: hr = %d\n", hr);
}

Learn more about using trials & trial extensions to win over prospective customers.

TurboActivate wizardActivating your product

We recommend you use the TurboActivate.exe for entering product keys and activating your product. Simply launch TurboActivate.exe and then check if the user is activated after it closes.

If you want to build your own interface then just use the TA_CheckAndSavePKey() and TA_Activate() functions. See the "API\C\Example.c" app in the TurboActivate packages.


Static TurboActivate library

In addition to the dynamic version (*.dll / *.so / *.dylib) we also provide static versions of TurboActivate (*.lib / *.a) that you can get on your API page. To use the static library you have to define "TURBOACTIVATE_STATIC" in your project, your makefile, or in your source before you include the "TurboActivate.h" header file.

Windows

We've built the TurboActivate static library for all variations of the C/C++ runtime library for both x86 and x64 platforms. When you're including the static library in your build you must ensure you're using the correct one or else you'll get a linker error like this:

error LNK2005: [function] already defined in MSVCRT.lib(MSVCR100.dll)

To find out what runtime library you're using, click the "Project -> [YourApp] Properties..." menu. In the dialog that pops up go to the "Configuration Properties" -> "C/C++" -> "Code Generation" node and look at the "Runtime Library" property:

Runtime Library

Use the TurboActivate static library that matches your runtime (in either the x86 or x64 folders):

TurboActivate-MT.lib   for Multi-threaded (/MT)
TurboActivate-MTd.lib  for Multi-threaded Debug (/MTd)
TurboActivate-MD.lib   for Multi-threaded DLL (/MD)
TurboActivate-MDd.lib  for Multi-threaded Debug DLL (/MDd)

If you're using the Multi-threaded runtime (/MT) the code would look like this:

#define TURBOACTIVATE_STATIC
#include "TurboActivate.h"
#pragma comment(lib, "TurboActivate-MT.lib")

Extra frameworks needed to use the static TurboActivatemacOS

When using the static TurboActivate library in macOS apps, in addition to including libTurboActivate.a in your project, you also need to add references to the following Frameworks and libraries:

Linux

When using the static TurboActivate library in Linux apps, in addition to including the libTurboActivate.a in your build scripts, you also need to compile with "-lrt". For example, here's how you would compile the Example.c app included in the "Static Linux package":

g++ -DNDEBUG -DTURBOACTIVATE_STATIC -m32 -o a.out Example.c ../../bin-linux/x86/libTurboActivate.a -lrt