C example

A simple C application that checks-out a single license

2025-11-29

QuidLM staff

There are only two essential steps in using QuidLM to implement licensing in your application. The security, validity, and license content are managed by QuidLM. To use that funtionality, you need to

  1. Initialize QuidLM. This is done with the qlm_init function. You can use this opportunity to provide the user's credentials. They come into play because licenses can be configured as available only to a subset of users. You are free to set the user email and password to NULL if you do not intend to use this functionality. If you initialize the license system without specifying user email and password, QuidLM will never give those licenses to your application.

     const char *user_email = NULL, *password = NULL;
     const char* error = qlm_init(user_email, password);
    

    The return value is NULL if everything went well and is an error message explaining the issue if there was one.

  2. Grab the license. The qlm_checkout_license takes two inputs - the license name and version. The license name is typically just the name of your product. The license version, if provided, should be in the major.minor format. The QuidLM will treat this input as the minimal license version that your current application is willing to accept. You normally pass the current version of your application for this parameter. That way, newer licenses enable older applications, but not vice versa, which is typically what you want. If for some reason that is not what you want, you can hard-code that version to "1.0" or some other constant.

     const char* product_name = "MyProduct", min_version = "3.1";
     const license_info_t* license_handle = qlm_checkout_license(product_name, min_version);
    

    If the returned license_handle is NULL, it means the requested license is not available, so your application needs to convey that information to the user and exit. If it is not NULL, the license_info_t structure contains the useful information about the license, such as its expiration date (license_handle->expiry) and custom parameters - a set of key-value pairs, which you, the developer, can use to set the application's behavior. For example, you can enable some features based on the presence of certain parameters: e.g., trial-license=true may prompt your application to display the "trial copy" badge somewhere. One other typical use of such a parameter is to limit the application performance, as in max-threads=10.

    The attributes of license_info_t are defined and explained in the license_api.h header file.

The above are the necessary parts, but you can take advantage of optional features, such as logging and license revocation. Those additional features are demonstrated in sample applications shipped with QuidLM. The demo_client application is a more full-fledged example, which can also be used for testing. It is a command line application that grabs the license specified on the command line for the specified number of seconds and prints the licensing information. The comments in the source code explain the standard functionality, such as the initialization and the license checkout mentioned above, and introduce the logging and the license revocation. The example is cross-platform - there are several #ifdef _MSC_VER sections to make it work on both Windows and UNIX systems.

/// Demo_client application: grab the specified license for
/// the specified length of time and print the licensing information.

#include <errno.h>      // EINTR
#include <stdatomic.h>  // atomic_bool
#include <stdio.h>      // printf
#include <stdlib.h>     // atoi

// The sleep function
#ifdef _MSC_VER
#    define WIN32_LEAN_AND_MEAN
#    include <Windows.h>
void sleep(unsigned int seconds)
{
    Sleep(seconds * 1000);
}
#else
#    include <unistd.h>
#endif

#include "license_api.h"

atomic_bool dead_license = false;

/// Output the error message in stderr and exit the process with the specified status.
void error_exit(int status, const char* message)
{
    fprintf(stderr, "%s\n", message);
    exit(status);
}

/// When the license is revoked, the application should react by saving the state, notifying the user, and exiting.
/// The function below is automatically called, for example, when the network connection to licensing service breaks.
/// This function is called from a separate thread, so it should be careful when accessing the global state.
/// For example, it can let the main thread (and potentially other threads) know by setting the global atomic flag.
/// Note that it should not call the standard library's exit function, as doing that in a thread is an undefined behavior.
/// For the purpose of demonstration, here we set the flag and print the message to the stderr.
void revocation_callback(const license_info_t* license_handle, enum revocation_reason reason)
{
    atomic_store(&dead_license, true);
    fprintf(stderr, "This application's %s license has been revoked: %s.\n", license_handle->product_name, qlm_revocation_reason(reason));
}

/// Check out the license for the specified product with the given version number (or higher),
/// print the license information, wait the specified number of seconds, and return.
int main(int argc, const char* argv[])
{
    if (argc < 2)
        error_exit(1,
                   "Expected some inputs on the command line.\n\n"
                   "  product_name: the product that you need the license for                  [required]\n"
                   "  min_version:  the minimum version of the product, in the major.minor format [1.0]\n"
                   "  duration:     exit application after this many seconds                       [2]\n\n");

    const char* const product_name = argv[1];
    const char* const product_version = argc < 3 ? "1.0" : argv[2];
    const int duration = argc < 4 ? 2 : atoi(argv[3]);

    // optional reaction to revoked licenses
    qlm_set_revocation_handler(revocation_callback);
    // set verbose log level for debugging
    // set_log_level(debug);
    // alternatively, set the environment variable: QLM_LOG_LEVEL=debug

    // Licenses can be configured as available only to a set of users.
    // If you initialize the license system without specifying user email and password, you will never receive those licenses.
    const char *user_email = NULL, *password = NULL;
    const char* error = qlm_init(user_email, password);
    if (error)
        error_exit(10, error);

    const license_info_t* license_handle = qlm_checkout_license(product_name, product_version);
    if (!license_handle)
        error_exit(2, "could not get the license");

    printf("Got license for product version %s.\n", license_handle->product_version);
    printf("Expiring %d.\nFloating: %s.\nLicense properties:\n",
           license_handle->expiry,
           license_handle->is_floating ? "true" : "false");
    for (int i = 0; i < license_handle->number_of_properties; ++i)
        printf("  %s: %s\n", license_handle->properties[i].name, license_handle->properties[i].value);

    sleep(duration);
    printf("Returning the license\n");
    bool status = qlm_checkin_license(license_handle);
    if (!status)
        error_exit(3, "License return failed");

    printf("Exiting\n");
    return 0;
}