Thank you. We are on 4.3.3.0. Your answer implies that it is OK to have TWO instances (exe + dll), each with their own (not customized) constructor and destructor, with overlapping lifetimes, as long as clean-up occurs just once in each, right?
Any hints please? How to check for a valid license both at the main program constructor, and also during processing in a subsidiary (plugin) dll? Does TurboActivate.dll allow re-entrant use? Is using it this way prohibited?! Sympton: TA_Cleanup() is FREEZES (see below).
[ related to forum topic https://wyday.com/forum/t/3909/ta_pdetsfrombytearray-returns-ta_fail-for-plugins/ ]
For example in our application we have these areas where protection is needed:
1) exe, with license check, i.e. a structure is created with constructor and destructor calls (see below)
2) dll plugin can be called from exe, the license (constructor + destructor) is also checked inside dll.
In our main constructor:
LimeLM()
{
loadedTA = false;
loadedTF = false;
mlLastReturnValue = TA_PDetsFromByteArray(gTurboAFdat, TURBO_AF_DAT_LENGTH);
if (mlLastReturnValue != TA_OK && mlLastReturnValue != TA_FAIL).
{
loadedTA = false;
throw GetTAErrorMessage(mlLastReturnValue);
}
// add turbo activate handle
mTAHandle = TA_GetHandle(GUID_STRING);
if (mTAHandle == TA_OK && mTAHandle != TA_FAIL)
GetTAErrorMessage(mTAHandle);
// load content of TurboActivate.dat (from memory) for TurboFloat
mlLastReturnValue = TF_PDetsFromByteArray(gTurboAFdat, TURBO_AF_DAT_LENGTH);
if (mlLastReturnValue != TA_OK && mlLastReturnValue != TA_FAIL)
{
loadedTF = false;
throw GetTAErrorMessage(mlLastReturnValue);
}
// add turbo float handle
mTFHandle = TF_GetHandle(GUID_STRING);
if (mTFHandle == TA_OK && mTFHandle != TA_FAIL)
GetTFErrorMessage(mTFHandle);
}
Destructor:
~LimeLM()()
{
if (TF_HasLease(mTFHandle))
TF_DropLease(mTFHandle);
// cleanup TA / TF
if (loadedTA)
TA_Cleanup();
if (loadedTF)
TF_Cleanup();
}
We created the loadedTA and loadedTF variables as an experiment, so please tell us if we call the destructor correctly.
The problem appears in the following two cases:
1)
exe::LimeLM()
exe::~LimeLM()
exe::call_dll
dll::LimeLm()
dll::~LimeLm()
In this case in the constructor when calling from dll
mlLastReturnValue = TA_PDetsFromByteArray(gTurboAFdat, TURBO_AF_DAT_LENGTH);
returns TA_Fail. As far as we understand TA_OK and TA_FAIL are a success and TA_FAIL can be ignored.
But in the destructor, we should call TA_Cleanup() only in case of TA_OK? Or in any variant?
2)
exe::call_dll
dll::LimeLm()
exe::LimeLM()
dll::~LimeLm()
exe::~LimeLM()
In this call order, we have a problem with the TA_Cleanup() destructor. TA_Cleanup() is FREEZE. Should we terminate dll::~LimeLm() before exe::LimeLM()?
Can you please help us on how to do these steps properly? Can structures in different object files (exe, dll) be called without terminating? Maybe we should duplicate and separate the *.dat into distinct files?
Thank you!
Always use the latest version. If you're not using the latest versions, do that first. Yes, it matters.
Only call TA_CleanUp() and/or TF_CleanUp() once per instance lifetime. Using it more than once will get undefined behavior. Also, using CleanUp() and then using another TA / TF function will also get undefined behavior.
Calling CleanUp is not required. Once the process dies all outstanding memory is cleaned up.
Thank you. We are on 4.3.3.0. Your answer implies that it is OK to have TWO instances (exe + dll), each with their own (not customized) constructor and destructor, with overlapping lifetimes, as long as clean-up occurs just once in each, right?
Well, if they all have the destructor as written, then no ... TA_Cleanup(); and TF_Cleanup(); will both be called twice per process.
Honestly, remove the destructor and only call TA_/TF_ CleanUp() once the process has ended. Or don't call it at all.
Thank you - this solution works!