Turbo Float in Qt5.0Solved

Hi,

I am trying to integrate Turbo Float into my application created using QT under Windows 7.

I pretty much copied the whole C example into my code as a start and got some errors.

TCHAR * featureName = _T("expiry");

error: C2440: 'initializing' : cannot convert from 'const char [7]' to 'TCHAR *'Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast

So, I did this...

TCHAR * featureName = (TCHAR *) _T("expiry");

did the same at 2 other places...

tfHandle = TF_GetHandle( (STRCTYPE) _T("18324776654b3946fc44a5f3.49025204"));

hr = TF_SaveServer(tfHandle, (STRTYPE) _T("127.0.0.1"), 13, TF_SYSTEM);

I was able to compile but it crashes, the moment tfHandle = TF_GetHandle( (STRCTYPE) _T("18324776654b3946fc44a5f3.49025204")); is executed.

Linus

Hey Linus,

TCHAR * featureName = _T("expiry");

error: C2440: 'initializing' : cannot convert from 'const char [7]' to 'TCHAR *'Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast

So, I did this...

TCHAR * featureName = (TCHAR *) _T("expiry");

Yikes, don't do that. You'll get your compiler to shut up, but you're not solving the problem (and it will likely result in a crash -- as you saw).

Here's the problem:

'const char [7]' to 'TCHAR *'

In other words, your app is compiled as an ANSI app, when it really needs to be compiled as a Unicode app. So, depending on your compiler, make the app use the Unicode charset. If you don't do that, then you can't use the "magic macros" like _T() or the TCHAR type. You'll instead have the prepend the string with "L" and use the wchar_t type. Like this:

wchar_t * featureName = L"expiry";

did the same at 2 other places...

tfHandle = TF_GetHandle( (STRCTYPE) _T("18324776654b3946fc44a5f3.49025204"));

hr = TF_SaveServer(tfHandle, (STRTYPE) _T("127.0.0.1"), 13, TF_SYSTEM);

Same problems. If you compile your app using the Unicode charset, then you shouldn't have a problem. If your compiler doesn't support, then you'll have to be explicit:

tfHandle = TF_GetHandle(L"18324776654b3946fc44a5f3.49025204");


hr = TF_SaveServer(tfHandle, L"127.0.0.1", 13, TF_SYSTEM);

Does that make sense?

I should have tried harder before I post...

The problem is because of missing DLL. I had to copy the DLL over.

However, when I ran the program, I cannot get a lease on the license.

Failed to get the floating license lease (TF_RequestLease() returned 9). Look in TurboFloat.h for a human readable explanation of the error.

It seems like a problem in the Handle. I did change the GUID in the example code to my own GUID.

Another thing is that I ran the TurboFloat Server in the same Windows 7 Laptop for testing.

Any help is appreciated.

Linus

Did you fix the Unicode strings that I mentioned? That still has to be fixed even if you're not getting crashes any more.

Sam,

thanks for your suggestion.

In my 2nd post, I mentioned I was able to get it to run by copying the DLL over. But I tried your suggestion anyway.I reverted my changes based on your recommendation by explicitly prepend L.

So, this new problem seems to be something else.

BTW, do you know where can I find a debug version of TurboFloat.lib?

Thanks!

Linus

So, this new problem seems to be something else.

Show me the code you're using and the return from each function call.

BTW, do you know where can I find a debug version of TurboFloat.lib?

The TurboFloat.lib will work in both debug & release versions of your app.

Sam,

I included the whole main.c below. The only thing different is the GUID, in the code below, I used the one from the example.

I do a qDebug() on the tfHandle and it returned "0".

hr = TF_RequestLease(tfHandle); returns "9".

#include "mainwindow.h"#include <QApplication>




#include <stdio.h>


/* Support Unicode compilation and non-Windows compilation */#ifdef _WIN32    #include <Windows.h>    #include <tchar.h>#else    #define _T(x) x    typedef char TCHAR;#endif


#include "TurboFloat.h"


uint32_t tfHandle;




// here we're just printing a license field.// of course, in your app you'll want to do something// useful with license fields.void PrintLicenseField(){    TCHAR * featureValue;


    //TODO: change this feature name to any licens field name    //      that you want to print out.


   // TCHAR * featureName = (TCHAR *) _T("expiry");    wchar_t * featureName = L"expiry";




    // if this app is activated then you can get a feature value (completely optional)    // See: http://wyday.com/limelm/help/license-features/




    HRESULT hr = TF_GetFeatureValue(tfHandle, featureName, 0, 0);


    featureValue = (TCHAR *)malloc(hr * sizeof(TCHAR));


    hr = TF_GetFeatureValue(tfHandle, featureName, featureValue, hr);


    if (hr == TF_OK)    {#ifdef _WIN32        wprintf(L"Feature value: %s\n", featureValue);#else        printf("Feature value: %s\n", featureValue);#endif    }    else        printf("Getting feature failed: %d\n", hr);


    free(featureValue);}


/* This function will be called by TurboFloat from a separate thread.   That means if you're displaying UI to your users you must ensure   that any windows (or any resource sharing for that matter) are   created in the right thread context or bad things might happen.


   Test this behavior well before releasing to your end-users. You can do that   by starting the TurboFloatServer with a short lease time. Then, on your test   computer where this app is running, unplug or disable your internet connection   to ensure your app can't contact the server (and thus TF_CB_EXPIRED_INET will   be passed to this function).*/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;


    // explicitly handle errors    // also, handle unknown statuses ("default")    // as errors.    case TF_CB_EXPIRED:    case TF_CB_EXPIRED_INET:    default:


        //TODO: disallow any features in your app.        printf("The lease expired before it could be renewed.\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;    }}










int main(int argc, char *argv[]){




    //Turbo float code




    /* Used to store TurboFloat responses. */    HRESULT hr;


    /* Get the handle that will be used for TurboFloat function calls.


       TODO: paste your Version GUID here.    */    //tfHandle = TF_GetHandle((STRCTYPE) _T("18324776654b3946fc44a5f3.49025204"));    tfHandle = TF_GetHandle(L"18324776654b3946fc44a5f3.49025204");


    qDebug() << tfHandle;


    /*       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);


    hr = TF_RequestLease(tfHandle);


    qDebug() << hr;


    if (hr == TF_E_SERVER)    {        /*           We're just harcoding 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.        */


        //hr = TF_SaveServer(tfHandle, (STRTYPE) _T("127.0.0.1"), 13, TF_SYSTEM);        hr = TF_SaveServer(tfHandle, L"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_WRONG_SERVER_PRODUCT)    {        /*          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;    }


    /*       The floating license lease requested successfully.


       Here's where you let your user start using your app.    */    printf("Floating license lease was requested successfully.\n\n");    printf("Type \"X\" and press Enter to \"drop\" the lease (make it available for other instances of your app) and then exit the app.\n\n");




    /* Here we'll just read in any license fields and print them out.


       Of course in your actual app you'll handle the license fields however you need       to (for instance, to limit functionality of your app).    */    PrintLicenseField();




    /* Loop until the user typed "X" to Release the lease and exit the app. */    while (getchar() != 'X') { }


    /* Drop the floating license, wait for the response, then exit your app. */    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. Look in TurboFloat.h for a human readable explanation of the error.\n", hr);


    /* Cleanup the memory. */    hr = TF_Cleanup();








    QApplication a(argc, argv);    MainWindow w;    w.showMaximized();    w.show();    w.setWindowTitle("Lucidus Validation Suite");


    return a.exec();}


If you're using Visual Studio then setting the "Character Set" in your project properties to "Unicode" will solve all of your problems. Why? Because right now you're using ANSI.

[attachment=0]char-set.png[/attachment]

What's the difference? When you're not using "Unicode' character set for the compiler:

TCHAR turns to "char"_T() does nothing to the string passed in.

So basically everywhere you see "TCHAR" or _T() it will fail because TurboFloat on Windows expects Unicode strings (wchar_t* not char*)

When you actually set the Unicode character set in your compiler then things will work, because:

TCHAR turns to "wchar_t"_T() prepends the "L" to strings (meaning they're Unicode string literals).

tfHandle = TF_GetHandle(L"18324776654b3946fc44a5f3.49025204");

Is that your correct GUID? Also, is the TurboActivate.dat file sitting in the same folder as the TurboFloat.dll file? It should be. What's the tfHandle? Is it 0?

Sam,

many thanks for your reply. It works now, I was able to retrieve one of the custom parameter in my license file.

I did not have TurboActivate.dat file sitting in the same folder as the TurboFloat.dll file.

I did a little research on MSVC using Qt, it seems like UNICODE is already defined by default. So, I have not really figured out why _T did not work. I will have to use the prepend of L method you highlighted.

So, really I had 3 problems.

1.I needed to manually prepend "L" at the 3 places.2. TurboFloat.dll must be copied to my own directory.3. TurboActivate.dat must be copied to my own directory.

Thanks!

Linus

Great, I'm glad you got it to work.

Sam,

I have a follow up question. Not sure if it is related.

I set up the license in such a way that there is only 1 active floating license (from the LimeLM dashboard). However, when I try to open up 2 copies of my app, both of them can get a license.

tfHandle returns "2" hr = TF_RequestLease(tfHandle); return "0"

I had modified my code in such a way that TF_DropLease is called only when the app exits.

Am I missing something, does the app have to specifically check for the number of current active lease?

Any thoughts?

Linus

If the 2 separate instances of your app are running in the same session and on the same computer, then they'll be allowed to run. TurboFloat Server won't stop that behavior. If you want your app to be single-instance (within the session) then you'll have to handle that within your app. What TurboFloat / TurboFloat Server does is limit the number of instances of your app that can run on separate computers or sessions.

So a way to test things is to run your app in one session on your computer, then switch to another user on the computer (while your app is still running on the other session) and run your app again on this new session. Your app running in this new session won't be able to get a lease.

Does that make sense?

Sam,

our client typically install the app on 1 server and multiple users will then log-in to invoke the app.

I assume then in that scenario, it will not be considered 1 session?

You also mentioned I can handle that in the app, can you shed some light? How can I query the license server to get that info?

Linus

I assume then in that scenario, it will not be considered 1 session?

Right, each user that logs into the server will be a separate session. TurboFloat handles that for you. In other words, if User1 logs into the server and starts your app, it will request a lease and start running if it gets it. Then, if User2 logs into the server (and User1 is still logger in and still using your app) then User2 won't be able to start your app because the 1 available license lease is being used by User1.

Does that make sense?

You also mentioned I can handle that in the app, can you shed some light?

TurboFloat already handles separate sessions and separate machines. However, if you want to also limit multiple instances within the same session then you'll have to read up on single instance (for example here).

Just note that you'll want the mutex to be "Local" not "Global".

Sam,

I understood the part on TurboFloat Server taking care of multiple instances.

So, the link you sent me. It means I have to manually limit the number of instances. That means.... even if I have more than 1 floating licenses, for each session only 1 instance of the software can be running.

The reason I ask is that our app can run in batch mode and we don't want user to submit jobs through a single session using only 1 license, but we want that to be possible as long as there are sufficient licenses.

Is there a way I can send a process ID or sort to identify each instances to the TurboFloat server?

Linus

I don't think I'm making myself clear. TurboFloat already handles the case where multiple users access a single centralized computer. That is, if your TurboFloatServer instance has only 1 available license lease, then only one of the users will be able to use your app on that server.

So if you have Joe, Bob, and Sally that all have access to the server, and any of them can log into the server at any time, only 1 of them will be able to run your app at any single time.

If Bob runs your app then he'll have exclusive access to the license lease until he closes your app. So if Sally tries to run your app when Bob is still running your app, then Sally will get an error message (TF_E_NO_FREE_LEASES -- you can print anything you'd like to the user that gets this error). Then when Bob shuts down your app, Sally will be able to successfully start your app in her session on the same computer.

In other words, TurboFloat already handles multiple sessions on the same computer. (Meaning we allow you to limit access to multiple sessions on the same computer) .

Is there a way I can send a process ID or sort to identify each instances to the TurboFloat server?

I'm a bit perplexed as to why you want to limit multiple instances of the same app within the same session. That is, if Bob started an instance of your app and then wanted to start another instances of your app in the same session. So, it's still just Bob running your app. And he's still on the same computer and on the same session.

Do you really want to limit that?

Sam,

take for example, the app is a simulator, it won't show anything meaningful to the user until end of simulation.

Bob can then run 100s of simulation with 1 license. Of course Joe and Sally can buy Bob a coffee and ask Bob to submit some more jobs on their behalf. After all, the results are what matters at the end of the simulation.

This is what we are trying to prevent.

Linus

This is an interesting use-case. So, let's say a customer buys a floating license product key for 5 license leases. What you want to do is let only 5 instances of your app run, correct? That is, if Bob runs 5 instances of your app then you want each instance of your app to take its own license lease even if it's running the same session. Is that what you're trying to do?

Sam,

Yes. This is actually quite common for EDA tools.

So, I assume at this point there is no way I can achieve this through Turbo Float?

Linus

Not currently. We can add it, though. I can see how this option might be useful. When would you need this by?

I am still on my 30 days trial from 2 days ago... 🙂 would be great if I can try before trial ends.

But realistically, I am pushing out to my beta customer first, I can live without this feature for first release if I can get an indication the wait time.

If you were to implement it, do you foresee if the app needs to figure out some sort of process ID or you think the Turbo Float server can figure it all out?

BTW, thank you so much for your support thus far.

Linus

But realistically, I am pushing out to my beta customer first, I can live without this feature for first release if I can get an indication the wait time.

Would six or seven weeks work for you? The feature itself isn't an enormous amount of work, but we have other things in the pipeline that we want to get out first.

If you were to implement it, do you foresee if the app needs to figure out some sort of process ID or you think the Turbo Float server can figure it all out?

It will all be handled within TurboFloat.

BTW, thank you so much for your support thus far.

I'm glad to help.

Sam,

apologies for the late response.

I think we can wait 7 weeks.

I would assume the feature would be tied to license file. This is so that someone using older server cannot run with new license file and thus overcome the new feature?

Linus

This is so that someone using older server cannot run with new license file and thus overcome the new feature?

No, the functionality will be built into the TurboFloat library and the TurboFloat Server. Plus you'd have to add a function call telling the TurboFloat library that you want to do per-instance lease requests.

Hi Sam,

I was wondering about the progress of the per-instance lease request.Like Linus, I'm working in the EDA business.With the exception of node-locked licenses, the per-instance license is the rule.

Our product is already on the market and we get more and more requests for floating licenses.

Exactly like Linus, we want to control the number of licenses our customers can run on their servers.

Thanks,Didier

PS: by the way, to far I really like how TurboActive is working

Hey Didier,

When the TurboFloat library (inside your app) requests a license lease from the TurboFloat Server, they're for particular user-sessions on the computer (rather than for the whole computer). This means user-sessions get their own "license lease" from the TFS. So every user running on the computer gets a separate license lease.

This also means that you can currently limit your app to 1 instance and ensure that every user can only run a single instance of your app.

We don't currently have per-instance license leases. We planned to add it to the upcoming 4.0 release, but we pushed that particular feature off so we could release sooner.

Short answer: you can already to 1-instance per user with TurboFloat. In an upcoming versions you'll be able to specifically do per-instance license leases (as an alternatively to the current per-user-session license leases).

Does that make sense?

Hey Sam,

Thanks for the quick reply.This makes perfect sense.

It's not really what I hoped for, but I'll work around by implementing a piece of software that will live between our app and TFS. This sw will take the instances in to account.

Thanks,Didier

We've since added per-instance leases to TF 4.1. Announced here: https://wyday.com/blog/2019/new-floating-license-model-per-instance-leases/