This article will give step-by-step instructions on how to add software licensing (specifically, hardware-locked or node-locked licensing) to your C# app. There's also a full example app (one Windows Forms example and one WPF example) 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 hardware-locked 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# app (using TurboActivate). To add floating-licensing to your C# app see the "Using TurboFloat with C#" article.
Before you can do anything, you need to login to your LimeLM account (or sign up). Then download TurboActivate for Windows on your API page. That file contains the TurboActivate.dll & TurboActivate.exe along with source code for a complete C# example app (in the "API\CSharp" directory).
Now we're going to walk you through each step you need to take in adding licensing, online activation, and timed-trials to your C# 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 you'll find 4 folders:
API: Contains all Windows source code examples. Inside this folder you'll find the "CSharp" project folder which contains the end-result of this tutorial. You'll also find the "TurboActivate.cs" file which you'll be adding to your app's project.
x64: Contains the 64-bit version of TurboActivate. This version only runs on 64-bit versions of Windows.
x86: Contains the 32-bit version of TurboActivate. This version runs on all versions of Windows. You'll be using this x86 version of TurboActivate with your application for this reason.
stdcall: Contains the "stdcall" versions of TurboActivate. You won't be using these with C#.
Now you need to add TurboActivate to your app. Add "TurboActivate.cs" from the "CSharp" project you extracted from the TurboActivate main package. You do this by right clicking your project in Visual Studio and clicking "Add -> Existing Items..." and browsing for the "TurboActivate.cs" file:
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.
Since you'll be using the x86 version of TurboActivate you'll have to set the "Platform target" to x86. After you do this your app will be able to run on both 32-bit and 64-bit machines without having to do complex installation scripts.
To set the target platform to x86 first click the "Project -> [Project Name] Properties" menu in Visual Studio. Click the "Build" tab on the right hand side. Then choose x86 from the "Platform target" dropdown:
Make sure you set this for both your "Release" and "Debug" configurations.
If instead of the x86 platform target you would rather choose the AnyCPU platform target then you need to make a few changes:
First you need to do add a "conditional compilation symbol" named TA_BOTH_DLL
(do this for both Debug and Release builds).
Next, include both the x86 and x64 versions of TurboActivate with your binaries. So copy the TurboActivate.dll from the x86 folder and put it in the Debug & Release folders. In the x64 folder rename TurboActivate.dll to "TurboActivate64.dll", and then copy that file to both your Debug & Release folders.
Lastly, if you're using the TurboActivate Wizard you need to copy the TurboActivate.exe file from the "x86" folder so that the wizard will be able to run on both 32-bit and 64-bit versions of Windows.
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).
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).
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 define the "ta
" variable in the "main form" class, and then create the TurboActivate object in the form's constructor:
public partial class Form1 : Form
{
readonly TurboActivate ta;
public Form1()
{
InitializeComponent();
try
{
//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.
Scroll up to your form constructor code and add a "bool" "isGenuine
" variable to save whether the customer is activated and genuine. 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:
readonly TurboActivate ta;
bool isGenuine;
// 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.
const uint DaysBetweenChecks = 90;
const uint GracePeriodLength = 14;
public Form1()
{
InitializeComponent();
try
{
//TODO: goto the version page at LimeLM and paste this GUID here
ta = new TurboActivate("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/
IsGenuineResult gr = ta.IsGenuine(DaysBetweenChecks, GracePeriodLength, true);
isGenuine = gr == IsGenuineResult.Genuine ||
gr == IsGenuineResult.GenuineFeaturesChanged ||
// an internet error means the user is activated but
// TurboActivate failed to contact the LimeLM servers
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 (!isGenuine && ta.IsActivated())
{
// 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.
ReVerifyNow frmReverify = new ReVerifyNow(ta, DaysBetweenChecks, GracePeriodLength);
if (frmReverify.ShowDialog(this) == DialogResult.OK)
{
isGenuine = true;
}
else if (!frmReverify.noLongerActivated) // the user clicked cancel and the user is still activated
{
// Just bail out of your app
Environment.Exit(1);
return;
}
}
}
catch (TurboActivateException ex)
{
// failed to check if activated, meaning the customer screwed something up
// so kill the app immediately
MessageBox.Show("Failed to check if activated: " + ex.Message);
Environment.Exit(1);
return;
}
// Show a trial if we're not genuine
// See step 9, below.
ShowTrial(!isGenuine);
}
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).
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.
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).
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
:
After you've created the menu item, changed the name to mnuActDeact
in the properties window, click the little lightning bolt, then double click the "Click" event and Visual Studio will automatically generate the event code for you:
Now we need to handle when the user clicks the Activate/Deactivate menu that you created. Scroll down to the "mnuActDeact_Click" function that Visual Studio generated for you. You can add code to Deactivate if the user is activated, or launch TurboActivate.exe if the user isn't activated:
void mnuActDeact_Click(object sender, EventArgs e)
{
if (isGenuine)
{
// deactivate product without deleting the product key
// allows the user to easily reactivate
try
{
ta.Deactivate(false);
}
catch (TurboActivateException ex)
{
MessageBox.Show("Failed to deactivate: " + ex.Message);
return;
}
isGenuine = false;
ShowTrial(true);
}
else
{
// Note: you can launch the TurboActivate wizard
// or you can create you own interface
// launch TurboActivate.exe to get the product key from
// the user, and activate.
Process TAProcess = new Process
{
StartInfo =
{
FileName = Path.Combine(
Path.GetDirectoryName(Application.ExecutablePath),
"TurboActivate.exe"
)
},
EnableRaisingEvents = true
};
TAProcess.Exited += p_Exited;
TAProcess.Start();
}
}
void p_Exited(object sender, EventArgs e)
{
// remove the event
((Process) sender).Exited -= p_Exited;
// the UI thread is running asynchronous to TurboActivate closing
// that's why we can't call CheckIfActivated(); directly
Invoke(new IsActivatedDelegate(CheckIfActivated));
}
delegate void IsActivatedDelegate();
void CheckIfActivated()
{
bool isNowActivated = false;
try
{
isNowActivated = ta.IsActivated();
}
catch (TurboActivateException ex)
{
MessageBox.Show("Failed to check if activated: " + ex.Message);
return;
}
// recheck if activated
if (isNowActivated)
{
isGenuine = true;
ReEnableAppFeatures();
ShowTrial(false);
}
}
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:
readonly TurboActivate ta;
bool isGenuine;
// 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).
readonly TA_Flags trialFlags = TA_Flags.TA_SYSTEM | TA_Flags.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.
const uint DaysBetweenChecks = 90;
const uint GracePeriodLength = 14;
public Form1()
{
InitializeComponent();
// ...
}
Now we have to make a few functions:
ShowTrial(bool show)
DisableAppFeatures()
ReEnableAppFeatures()
In the ShowTrial
method you can show how many trial days remain for the user. You can open the CSharp 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:
void ShowTrial(bool show)
{
lblTrialMessage.Visible = show;
btnExtendTrial.Visible = show;
mnuActDeact.Text = show ? "Activate..." : "Deactivate";
if (show)
{
uint trialDaysRemaining = 0;
try
{
ta.UseTrial(trialFlags);
// get the number of remaining trial days
trialDaysRemaining = ta.TrialDaysRemaining(trialFlags);
}
catch (TurboActivateException ex)
{
MessageBox.Show("Failed to start the trial: " + ex.Message);
}
// if no more trial days then disable all app features
if (trialDaysRemaining == 0)
DisableAppFeatures();
else
lblTrialMessage.Text = "Your trial expires in " + trialDaysRemaining + " days.";
}
}
Now you can add the functions to your code to disable and enable your application features:
void DisableAppFeatures(bool timeFraudFlag = false)
{
//TODO: disable all the features of the program
}
void ReEnableAppFeatures()
{
//TODO: re-enable all the features of the program
}
In the example CSharp 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. And, while you're there, add an event handler for the "Trial Changed" event:
public Form1()
{
InitializeComponent();
try
{
ta = new TurboActivate("Paste GUID Here");
// set the trial changed event handler
ta.TrialChange += trialChange;
// ... IsGenuine() code from above goes here
}
catch (TurboActivateException ex) { /* Handle exception */ }
ShowTrial(!isGenuine);
}
With the event handler you'll be able to disable features in your app at runtime without having to poll TurboActivate's functions. It will handle the details of detecting normal trial expiration as well as unusual behavior with the customer's date/time settings (various types of client-side fraud):
void trialChange(object sender, StatusArgs e)
{
// disable the features of your app
DisableAppFeatures(e.Status == TA_TrialStatus.TA_CB_EXPIRED_FRAUD);
}