NI TestStand

cancel
Showing results for 
Search instead for 
Did you mean: 

Set C module FunctionName via API

Hello,
 
I have programmed an edit substep for a C dll call step in TestStand. In the edit dialog, the user can choose between some functions that the step should execute. I then set the DllModule.FunctionName property, delete all parameters except the return value and create all parameters that the chosen function needs. When checking the result in the "Specify Module..." dialog, everything looks fine.
When executing the sequence, the dll function throws an exception. When I debug into the c code, I can see that the paramters are not passed correctly. Depending on the differences in the function prototypes before and after changing the module properties programmatically, the parameter values are e.g. shifted by four bytes in memory. Looks like some internal information doesn't get updated when I change the FunctionName.
There are two ways to get the sequence working:
  • Saving, closing and re-opening the sequence file helps. Everything looks the same as before, but it works. (Unloading all modules does not help!)
  • When I choose a different function in the specify module dialog, click OK to close the dialog, open it again and choose the desired function again, it works, too.

Obviously, the Specify module dialog does more than only setting the FunctionName property when I choose a function. I have tried to find a TestStand API function that I can call in order to get it working, but without success. Unloading the module doesn't help, nor does LoadPrototype (which returns false as my dll functions are declared extern "C").

There is another little problem that might be related to this: The step description in the sequence view is not updated. It should show "FunctionName (ModuleName)", but when changing the function name via the API, it keeps the old value. The tooltip works, though! This reminds me of an older post, but the answer doesn't help me:

http://forums.ni.com/ni/board/message?board.id=170&message.id=203375&query.id=334292#M203375

Thanks for your help!

Matthias

0 Kudos
Message 1 of 10
(4,038 Views)
Hello,

I'm not sure if the edit substep function will work in that way you described. Which version of TestStand do you use?

Could you please post and example sequence with your steptype including the edit substep code to verify your issue?

Thanks and regards,

Nikolai
0 Kudos
Message 2 of 10
(3,996 Views)

Hello Nikolai,

I have been able to simplify the problem:

As it seems, changing the DllModule.AsCommonCModule().FunctionName does not work. After changing the function call via the API, the previous function is still called until you reload the sequence.

I have attached two VS2005 projects:

One .NET project containing the edit dialog (EditTestFunctions)

One C project containing two exported functions (TestFunctions). Each function does nothing but showing a Message box with the function name.

I also included a sample sequence in the zip file.

If you follow these steps, you will (hopefully) see my problem: Open the sequence, run it and check that the test step shows the correct function name. Open the edit dialog, check the other radio button, click OK. In the specify module dialog, you will see that the function name was actually changed. Running the sequence again still shows the other function name. Save the sequence, close and re-open it, and the sequence will run correctly.

I am using TestStand V3.5

Thanks

Matthias

0 Kudos
Message 3 of 10
(3,975 Views)
Hi Matthias,

the problem is that one cannot change the module while it is loaded.

Enter the following command to your edit substep code (f.ex. when closing the panel):

_seqContext.Engine.UnloadAllModules();

You can also do an unload in the step options to solve the issue.

regards,

Nikolai

0 Kudos
Message 4 of 10
(3,967 Views)
You can use _seqContext.Step.Module.Unload() to unload the module for just that step.

Starting with TestStand 4.0, setting the FunctionName and other module properties will automatically unload the module for you.
0 Kudos
Message 5 of 10
(3,959 Views)

Hi,

you are right. If I call UnloadAllModules or Module.Unload, the correct function will be executed. But there is another problem that still isn't solved (I simplified my example a bit too much):

If the two functions have different parameters, they are not called correctly. I have changed my code like this:

private

void ConfigDialog_FormClosing(object sender, FormClosingEventArgs e)

{

_seqContext.Engine.UnloadAllModules();

DllModule dllModule = _seqContext.Step.Module as DllModule;

if (dllModule != null)

{

while (dllModule.Parameters.Count > 1)

{

dllModule.Parameters.Delete(1);

}

if (rbOne.Checked)

{

dllModule.AsCommonCModule().FunctionName =

"FunctionOne";

dllModule.Parameters.New(1,

"param1", "1", DllParameterCategories.DllParamCategory_Numeric, CommonCParameterPassOptions.CParamPass_ByVal, CommonCParameterTypes.CParamType_Int32);

}

else

{

dllModule.AsCommonCModule().FunctionName =

"FunctionTwo";

dllModule.Parameters.New(1,

"param1", "2", DllParameterCategories.DllParamCategory_Numeric, CommonCParameterPassOptions.CParamPass_ByVal, CommonCParameterTypes.CParamType_Int32);

dllModule.Parameters.New(2,

"param2", "3", DllParameterCategories.DllParamCategory_Numeric, CommonCParameterPassOptions.CParamPass_ByVal, CommonCParameterTypes.CParamType_Int32);

}

}

base.OnClosing(e);

}

The functions in the C dll look like this, now:

__declspec

(dllexport) void FunctionOne(int param1)

{

AFX_MANAGE_STATE(AfxGetStaticModuleState());

char buffer[100];

sprintf(buffer,

"FunctionOne, param1 = %d", param1);

AfxMessageBox((LPCTSTR)buffer);

}

__declspec (dllexport) void FunctionTwo(int param1, int param2)

{

AFX_MANAGE_STATE(AfxGetStaticModuleState());

char buffer[100];

sprintf(buffer,

"FunctionTwo, param1 = %d, param2 = %d", param1, param2);

AfxMessageBox((LPCTSTR)buffer);

}

Now, after changing the function name, the correct function is executed, but with wrong parameters. If I execute FunctionTwo first and then switch to FunctionOne, param1 of FunctionOne is 0 instead of 1. When I look at the RAM in the debugger, I can see that the parameter value 1 is at an address 4 bytes too high. The other way round (first FunctionOne then FunctionTwo), param1 of FunctionTwo gets the value for param2 (3), param2 is 0.

Are there more Unload functions that take care of the parameters as well?

Thanks!

Matthias

0 Kudos
Message 6 of 10
(3,951 Views)
Matthias,

i am not sure, but i think i cannot reproduce the exact issue you are seeing....
Here is what happens at my system when implementing your code (with one difference):
- Loading the sequence in TS 3.5 and executing it calls the dialog with "Function One, param1 = 0".
- Restart the execution returns same result (as expected)
- Editing to Function One creates dialog "Function One, param1 = 0"
- Editing to Function Two creates dialog "Function Two, param1 = 2, param2 = 3". This is what i would expect.
- Editing back to Function One creates dialog "Function One, param1 = 0".

So it seems that only function one has some problems with its parameters. The difference i have in my code is that i do the UnloadAllModules in the "OnLoad" of the Editmodule.

I made some further testing and (this maybe good news for you) the issue never appeared in TS 4.0. So even function one got the correct parameters.....

hope this helps,
Norbert B.
Norbert
----------------------------------------------------------------------------------------------------
CEO: What exactly is stopping us from doing this?
Expert: Geometry
Marketing Manager: Just ignore it.
0 Kudos
Message 7 of 10
(3,940 Views)

Hello,

the error with Function Two occurs when you save the file while Function One is selected, close it and open it again. After that, Function One works and Function Two doesn't. But even if the error was only with Function One: There must be a possibility to get this to work because when I do the changes manually in the Specify Module dialog, everything works. As far as I know, the sequence editor also uses the TestStand API, so if I find out which API functions it uses, my code should work, too.

I'm afraid I cannot switch to TestStand 4.0 in this project.

Regards,

Matthias

 

0 Kudos
Message 8 of 10
(3,939 Views)
TestStand computes and caches in memory information about the stack based on the parameters. The Specify Module dialog updates this information when it changes the set of parameters, but there isn't an API method to update this information. You can workaround this problem by taking advantage of the fact that the Clone method does clear the cached information. See the example below. Also, your code should be calling SequenceFile.IncChangeCount method so that the Sequence Editor refreshes correctly for the changes. Insert the following code after you change the parameters on the dllModule.


// Unload module because we changed the module specification.

_seqContext.Step.Module.Unload();

 

// Clone module and replace it with the clone to clear the cached parameter information.

PropertyObject module = dllModule as PropertyObject;

PropertyObject moduleClone = module.Clone(string.Empty, PropertyOptions.PropOption_CopyAllFlags | PropertyOptions.PropOption_DoNotShareProperties);

module.SetPropertyObject(string.Empty, 0, moduleClone);

 

// Increment change count so Sequence Editor refreshes.

_seqContext.SequenceFile.IncChangeCount();


Message 9 of 10
(3,917 Views)

Thanks a lot, that solves all the issues! Smiley Very Happy

Regards, Matthias

0 Kudos
Message 10 of 10
(3,904 Views)