NI TestStand

cancel
Showing results for 
Search instead for 
Did you mean: 

API testStand for ModuleAdpater DotNet

Hello,

 

I try to use the function TS_DotNetModuleGetParameters to get paramaters of a function include in a .dll.

No error is detected but it seems that the parameters is empty. Because when I count items with TS_DotNetParametersGetCount, the method return 0.

 

The paramaters of  TS_DotNetModuleGetParameters look correct.

 

Someone have any ideas of the problem?

 

 

Thanks a lot,

Anthony

0 Kudos
Message 1 of 42
(5,765 Views)

Anthony -

 

Calling the TS_DotNetModuleGetParameters function in CVI corresponds to getting the DotNetModule.Parameters property. The TestStand Help for DotNetModule.Parameters states that before calling this method, you must call DotNetModule.LoadPrototypeFromMetadataToken() befor calling DotNetModule.Parameters.

 

Are you calling TS_DotNetModuleLoadPrototypeFromMetadataToken before calling TS_DotNetModuleGetParameters?

 

Hope this helps.

Message Edited by Manooch_H on 12-08-2009 10:36 AM
Manooch H.
National Instruments
0 Kudos
Message 2 of 42
(5,727 Views)

Hello Manooch H,

 

Yes, I'm calling TS_DotNetModuleLoadPrototypeFromMetadataToken before calling TS_DotNetModuleGetParameters.

I tried before with an obsolete method TS_DotNetModuleLoadMemberInfo but it doesn't work too. May be I forget something?

 

Have you got an example for me?

 

I show a part of my code :

 

if (sModulePath != NULL && strcmp(sModulePath, "") != 0) { tsApiErrChk(TS_DotNetModuleSetAssembly(hTSStepModule, &errorInfo, TSConst_DotNetModule_AssemblyLocation_File, sModulePath), TS_ERROR); } else if ( iStepType != TS_StepType_CustomValue ) { tsErrThrow(TS_ERROR_NOMODULEPATH, TS_ERRMSG_DOT_NOMODULEPATH, TS_ERROR); } if (sClassName != NULL && strcmp(sClassName, "") != 0) { tsApiErrChk(TS_DotNetModuleSetClassName(hTSStepModule, &errorInfo, sClassName), TS_ERROR); } else if ( iStepType != TS_StepType_CustomValue ) { tsErrThrow(TS_ERROR_NOCLASSNAME, TS_ERRMSG_DOT_NOCLASSNAME, TS_ERROR); } generateObjectReferenceName(sModulePath, szObjectReferenceName); tsApiErrChk(TS_DotNetModuleSetClassReference (hTSStepModule, &errorInfo, szObjectReferenceName), TS_WARNING); tsApiErrChk(TS_PropertyExists (hTSMainSequence, &errorInfo, szObjectReferenceName, TS_PropOption_NoOptions, &bExists), TS_WARNING); if (!bExists) { tsApiErrChk(TS_PropertyNewSubProperty (hTSMainSequence, &errorInfo, szObjectReferenceName, TS_PropValType_Reference, VFALSE, "", TS_PropOption_NoOptions), TS_WARNING); tsApiErrChk(TS_DotNetModuleSetCreateObject (hTSStepModule, &errorInfo, VFALSE), TS_WARNING); } if (sFunctionName != NULL && strcmp(sFunctionName, "") != 0) { tsApiErrChk(TS_DotNetModuleSetMemberType(hTSStepModule, &errorInfo, TSConst_DotNetMember_CallMethod), TS_WARNING); tsApiErrChk(TS_DotNetModuleSetMemberName(hTSStepModule, &errorInfo, sFunctionName), TS_ERROR); } else if ( iStepType != TS_StepType_CustomValue ) { tsErrThrow(TS_ERROR_NOFUNCTION, TS_ERRMSG_DOT_NOFUNCTION, TS_ERROR); } //tsApiErrChk(TS_DotNetModuleLoadMemberInfo (hTSStepModule, &errorInfo, VFALSE, &bHasMemberInfo), TS_ERROR); tsApiErrChk(TS_DotNetModuleGetMetadataToken (hTSStepModule, &errorInfo, &metadata), TS_ERROR); tsApiErrChk(TS_DotNetModuleLoadPrototypeFromMetadataToken (hTSStepModule, &errorInfo, metadata, 0, &bHasMemberInfo), TS_ERROR);

 and after, I do :

 

 

// iModuleAdapter = [rechercher le module adapter spécifié dans le step] iModuleAdapter = getModuleAdapter(); if (iModuleAdapter == TS_ModuleAdapter_None) { tsErrThrow (TS_ERROR_UNKNOWNMODULEADAPTER, TS_ERRMSG_UNKNOWNMODULEADAPTER, TS_ERROR); } // hTSStepModule := [obtenir le module du step créé] tsApiErrChk(TS_StepGetModule (hTSNewStep, &errorInfo, &hTSStepModule), TS_ERROR); if ( iModuleAdapter != TS_ModuleAdapter_SequenceCall ) { // hParametersList := [rechercher la liste des paramètres] tsApiErrChk(getParametersList(iModuleAdapter, hTSStepModule, &errorInfo, &hTSParametersList), TS_ERROR); // lNbParam := [rechercher le nombre de paramètres] tsApiErrChk(getParametersCount (iModuleAdapter, hTSParametersList, &errorInfo, &lNumberOfParameters), TS_ERROR); // WHILE (index < lNbParam AND NOT bParamFound) // DO // hLbvParameter := [rechercher le paramètre à l'index courant] // sCurParamName := [rechercher le nom du paramètre courant] // IF (sCurParamName == sParamName) THEN // [mettre la valeur du paramètre à sValueExpr] // bParamFound := TRUE // FI // [liberer le handle hLbvParameter] // OD // [liberer le handle hLbvParameters] for (iIndex = 0; iIndex < lNumberOfParameters && !bParameterFound; iIndex++) { tsApiErrChk(getParametersItem (iModuleAdapter, hTSParametersList, &errorInfo, iIndex, &hTSParameter), TS_ERROR); tsApiErrChk(getParameterName (iModuleAdapter, hTSParameter, &errorInfo, &sParameterName), TS_ERROR); if ( strcmp (sParameterName, sParamName) == 0) { tsApiErrChk(setParameterValueExpr (iModuleAdapter, hTSParameter, &errorInfo, sValueExpr), TS_ERROR); bParameterFound = VTRUE; } CA_DiscardObjHandle(hTSParameter); } }

 Thanks,

Anthony

 

0 Kudos
Message 3 of 42
(5,717 Views)

Moreover, the function TS_DotNetModuleGetMetadataToken returns metadata=-1. So I think, I've done an error before this function.

 

Anthony

 

0 Kudos
Message 4 of 42
(5,714 Views)

Anthony -

 

Please provide an explanation of what you are trying to do along with an example assembly for which you wish to accomplish this task and I will try to provide a simple example of doing so.

Manooch H.
National Instruments
0 Kudos
Message 5 of 42
(5,710 Views)

I do a software which can automatically generate TestStand sequences from a model. (For information it's called MaTeLo but it's not the topic! lol)

 

And this software can create steps in sequence TestStand with different module adapters like sequence call, CVI, labview, Dll,... But it doesn't work with the dot net adapter and i don't know why.

 

(If you want an evaluation licence of our software for understanding, i can send it)

 

Anthony

0 Kudos
Message 6 of 42
(5,693 Views)

Anthony -

 

It turns out that this isn't a trivial implementation. I am working on putting together an example that will help you accomplish this task. I will attach it to this thread when I have completed it.

 

Thanks for your patience.

Manooch H.
National Instruments
0 Kudos
Message 7 of 42
(5,648 Views)

Thank you for your help. I look forward to your message.

 

Anthony

0 Kudos
Message 8 of 42
(5,638 Views)

Anthony -

 

Currently, functionality for retrieving the Metadata Token for a class constructor or member is not fully provided in the TestStand .NET Adapter API. The DotNetModule.GetConstructorMetadataToken() and DotNetModule.GetMetadataToken() methods only return the correct Metadata Token when the member/constructor prototypes have already been loaded. Thus, in the case of your code, when you call DotNetModule.GetMetadataToken(), the method is returning -1 because the member prototype for the Step you are referring to has not yet been loaded.

 

This leaves you with a few options for moving forward. The DotNetModule.LoadConstructorPrototypeFromMetadataToken() and DotNetModule.LoadPrototypeFromMetadataToken() methods will function properly when provided with a correct Metadata Token. In order to get the Metadata Token for the required constructor/member, you can use one of the following approaches:

 

Get Metadata Token from IL DASM

  • Use IL DASM to get the necessary Metadata Token. ILDASM.exe is a tool that installs with Visual Studio. To launch it, browse to Start»Programs»Microsoft Visual Studio 200x»Visual Studio Tools»Visual Studio 200x Command Prompt.
  • In the command prompt, type ILDASM.exe and hit Enter.
  • Once IL DASM pops up, select File»Open and browse to the assembly which will be called by the step you are programmatically creating.
  • Next, select View»Show token values.
  • You can now double click on a method or constructor which will result in a dialog box from which you can get the hexadecimal representation of the method/constructor's Metadata Token (see image below).

    ILDASM.png
  • You can then convert this hexadecimal number to a decimal number and pass it as the Metadata Token parameter of the DotNetModule.LoadConstructorPrototypeFromMetadataToken() or DotNetModule.LoadPrototypeFromMetadataToken() method.


Get Metadata Token from TestStand

  • You can use TestStand to get your necessary Metadata Token values if you've already configured a step.
  • In TestStand, create a .NET Step that calls your assembly and configure the Class, Constructor, and Member fields.
  • In the next step you can call PreviousStep.Module.AsDotNetModule.GetConstructorMetadataToken() and PreviousStep.Module.AsDotNetModule.GetMetadataToken() to get the Constructor and Member Metadata Token values.
  • You can then use these decimal values to pass to the Metadata Token parameter of the DotNetModule.LoadConstructorPrototypeFromMetadataToken() and DotNetModule.LoadPrototypeFromMetadataToken() methods.

 

Create your own tool to get Metadata Tokens

  • You can create a .NET Assembly and use Reflection to get the Metadata Token for the Constructor or Member of your choice.
  • This would involved calling Assembly.Load() or Assembly.LoadFrom() to load the assembly that you want to use in your step.
  • You could then use  Assembly.GetType(string name) to get a reference to the type where "name" is the full name of your class (namespace.class).
  • From here you could use one of the methods of the Type class to get the appropriate Constructor or Member.
  • Finally you could get the MetadataToken property from the Constructor or Member.
  • This approach will not be trivial as you have to be aware of and account for the possibility of multiple Constructor definitions and Method overloads. I have attached an example C# project along with a TestStand sequence file to demonstrate a simple implementation of this approach. Open createDotNetStep_40.seq. After running the MainSequence of this sequence file, a new .NET step will be created in the DotNetSequence sequence configured to call myTestAssembly.dll. When you run the MainSequence, it will call into GetMetaDataToken.dll once to get the Metadata Token for the Constructor and once to get the Metadata Token for the Metho. It will then use the TestStand API in an expression statement to programmatically create the step.
  • Note that the implementation of the GetMetaDataToken.dll that I've provided is very simplistic and specific to the example that I've created. Modifications will need to be made to make the implementation more robust and capable of handling the caveats I mentioned in the previous bullet. Also, you will have to update some of the hard-coded paths to match the paths on your machine.
  • Once you've completed a satisfactory implementation of your own tool, you can then use CVIs built-in .NET library to call it or you can use the Create .NET Controller tool to create an instrument driver for your assembly that can be called from CVI.


Hope this helps. Please let me know if you have any questions.

Message Edited by Manooch_H on 12-14-2009 03:01 PM
Manooch H.
National Instruments
Message 9 of 42
(5,600 Views)
Thank u i used LoadPrototypeFrom MeteDataToken() method.it worked out , but it is not setting the parameter for the value field in the return parameters.how can i do that
0 Kudos
Message 10 of 42
(5,481 Views)