NI TestStand

cancel
Showing results for 
Search instead for 
Did you mean: 

Problem unloading c++ dll

I have a dll in c++ which has a variable used in different functions in the class (so value is not set in function but when we call dll first). One of them, xyz, is set to true when we load the dll.

 

I have a MainSequence with 2 sequence calls. Everything is in the same sequence file.

In each of the 2 sequences, I call the same dll (lets call it Comm.dll).

 

In the first sequence, the variable xyz is set to false since I cant establish the connection. In the second sequence, I call back the function in Comm.dll and expect the xyz to have the value True but it is still at false (due to the previous call).

 

It seems the dll doesn't get unloaded.

 

My steps calling the dll are set to Load dynamically and to Unload after step executes. I also unchecked the Optimize reentrant calls from the sequences (not sure if it makes a difference).

 

It still continue to not unload the dll.

 

The only way I can work-around it is to call an Engine.UnloadAll() at the end of the first sequence. I don't want to do that because I don't want developpers to think about doing that all the time when creating sequences.

 

And I don't understand why it doesn't unload. I'm calling the dll at 3 places in the whole executions, all are load dyn. and unload after step execute. I'm also not using a Process Model, only running the MainSequence. (Also, the sequence file unload/load options are Use Step Load Options. I tried to set them to Load dyn./Unload after Step with the same result).

 

Any ideas why I get that behavior? Thanks for your help.

 

 

0 Kudos
Message 1 of 7
(5,976 Views)

Hi MatLaroche,

 

What version of TestStand are you using?  I tried to reproduce this by creating a dll that sets a global variable to 1, then has one exported function to return the value of the variable.  In the function, if the variable is equal to 1, it sets the variable to 2 and returns the value of the variable.  If the variable is not equal to 1, it sets it to 0 then returns.  This shows that if the function is called after the dll is loaded or reloaded, it will return 2.  All subsequent calls to the function will return 0.

 

I made a test sequence with two subsequences.  Each subsequence calls the function and has the Load/Unload options set to Load dynamically and Unload after step executes.  I tried checking and unchecking the Optimize reentrant calls in the sequence properties, but it didn't seem to make a difference.

 

How are you setting the value of this variable initially?  I set up a global variable and just set the value there.  Here is my code (written with CVI 9.0):

 

Code:

#include <cvirte.h>

int var=1;

 

//DllMain generated by CVI

int __stdcall DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
    switch (fdwReason)
    {
        case DLL_PROCESS_ATTACH:
            if (InitCVIRTE (hinstDLL, 0, 0) == 0)
                return 0;      /* out of memory */
            break;
        case DLL_PROCESS_DETACH:
            CloseCVIRTE ();
            break;
    }
   
    return 1;
}

int DLLEXPORT ReturnVar()
{
    if(var == 1)
    {
        var = 2;
        return var;
    }
    var = 0;
    return var;
}

Eric B.
National Instruments
Message 2 of 7
(5,949 Views)

I'm using TS 4.1.1.

 

Your example is similar to my code structure. I don't have CVI installed on my laptop right now to test it, but you get the idea.

I've put in attachment the source code. Maybe by inspection you can spot what is wrong. I'm not a c++ expert, so I might have done something weird.

 

The global flag is timeoutOnReceive. It is set to false initially.

bool CPIDCommunicationDLLApp::timeoutOnReceive = false;

 

I call the function InitializeConnection() for the first time and a timeout occurs (it is expected).

            if(mWaitForMsgCount > timeoutReceiveCount)
            {
                timeoutOnReceive = true;
            }

 

When I do a second call in Teststand to InitializeConnection(), the timeoutOnReceive is true again (but should be reinitialize to false since I unloaded dll). The communication is definitely ok on second call and shouldn't timeout (and I know that because it doesn't wait the timeout (10 seconds). I receive the data in the first second, but wrongly go in the condition triggered by a  timeoutOnReceive.

//If no data received (timeout)
                    if(timeoutOnReceive == true)
                    {
                        *errorCode = 300;
                        errorMessageStr = "Timeout when waiting for RX data.";

 

I also know communication is working because if I call an Engine.UnloadAll(), it will work the second time (as expected).

 

Thanks for your help. I'll try to do a simpler dll and test it. It might be my c++ coding causing this weird behavior though.

 

(Work-around is to set the flag to false each time I enter the function, but that doesn't explain why it doesn't unload the dll.)

Download All
0 Kudos
Message 3 of 7
(5,940 Views)

My sequence file contains only one sequence (the MainSequence).

 

I have 4 steps in it:

 

Reset (which reset the UUT)

Initialize (which timeout since UUT is booting)

Statement (with code Runstate.Engine.UnloadAll())

Initialize (which doesn't timeout since the 10seconds of the first initialize is enough for the UUT to respond)

 

If I set the run mode of the Statement step to skip, i get timeout for first Initialize AND second Initalize.

If the Statement runs between them, I get timeout only for first statement.

 

Like I said, everything is Load dynamically and unload after step executes. And seqfile options is set to Use step settings.

 

I don't have any other sequences or step that could cause the dll to stay loaded.

0 Kudos
Message 4 of 7
(5,936 Views)

Mat,

 

What happens if you set the unload option to unload after sequence executes?  We are currently investigating an issue where a module will not unload after the step executes if the step encounters a run-time error (even though the unload option is set to Unload after step executes), but we have not seen a case like this where you are ignoring the run-time error (even though it may occur).  If this resolves the issue, I would suggest doing that for now.  The bug report reference number for this issue is 131559.  When new versions of TestStand are released, the release notes list a list of bugs that were fixed in the latest version along with their reference numbers.  So when a new version of TestStand comes out, you can check to see if this bug has been fixed.

Eric B.
National Instruments
Message 5 of 7
(5,930 Views)

When I set unload option to unload after sequence executes, I have the same result (it is expected since the 2 steps are in same sequence, no?).

 

I have one parameter in my function and it seems if I set the property Result Action to "No Action", the dll unloads correctly after steps.

If I set it to "if != 0 Set Error.Occured to True", then the dll doesn't unload and the second call to it doesn't reinitialize the global variables.

 

The bug seems to be there, using the property Result Action with a value different then No Action cause the bad behavior (dll is not unloaded).

 

Thanks for the bug #, I'll do a work-around until it is fix.

0 Kudos
Message 6 of 7
(5,893 Views)

Mat,

 

Yes, I'm sorry I was unclear.  When I mentioned the "unload after sequence executes" option, I was thinking of your original question where you had MainSequence calling into the two different subsequences and you were seeing that the dll was not unloaded between sequences.

 

Thanks for the additional information...this will be helpful in debugging and trying to find the root cause of the problem for the developers.

Eric B.
National Instruments
0 Kudos
Message 7 of 7
(5,852 Views)