NI TestStand

cancel
Showing results for 
Search instead for 
Did you mean: 

Unreleased references using engine API in C++

Hi,

 

I am writing a little remote control tool to run TestStand silently in C++ and am having trouble shutting down the engine properly. This is the state which is still working for me:

Spoiler
// This is the .cpp file of a MS Visual C++ 2010 win32 console application

#include "stdafx.h"
#import "teapi.dll"

int _tmain(int argc, _TCHAR* argv[])
{
    HRESULT hr;
    TS::IEnginePtr teapi;
    TS::SequenceFilePtr seqfile;

    hr = CoInitialize(NULL);                            // initialize COM
    hr = teapi.CreateInstance(__uuidof(TS::Engine));    // initialize TestStand API
    
    seqfile = teapi->GetSequenceFileEx("C:\\test.seq",0,TS::ConflictHandler_Error);
    
    teapi->ReleaseSequenceFileEx(seqfile,0);
    teapi->ShutDown(true);

    return 0;
}

This is even working  without the line "teapi->ShutDown(true);", but of course it doesn't do a whole lot.

The trouble begins as soon as I want to actually execute test.seq (which is a trivial sequence containing two waits and a pass/fail test without adapter):

Spoiler
// This is the .cpp file of a MS Visual C++ 2010 win32 console application

#include "stdafx.h" #import "teapi.dll" int _tmain(int argc, _TCHAR* argv[]) {     HRESULT hr;
    TS::IEnginePtr teapi;
    TS::SequenceFilePtr seqfile;
    TS::ExecutionPtr execution;

    hr = CoInitialize(NULL);                            // initialize COM
    hr = teapi.CreateInstance(__uuidof(TS::Engine));    // initialize TestStand API
    
    seqfile = teapi->GetSequenceFileEx("C:\\test.seq",0,TS::ConflictHandler_Error);
    
    execution = teapi->NewExecution(seqfile,"MainSequence",NULL,false,0);
    execution->WaitForEndEx(-1,true);                    // seqfile->CanUnload == true after this line

    teapi->ReleaseSequenceFileEx(seqfile,0);
    teapi->ShutDown(true);

    return 0; }

This creates the following TestStand Debug Options Warning:

Spoiler
The Station Option, Report Objects Leaks and Reported Known OS and Component Problems,
reported the following warnings on shutdown:

References to PropertyObjects were not released properly. Total number of objects: 87 Number of top-level objects: 11 Note: Some top-level objects may be included if they are referenced by an incorrectly released top-level object. For example, an unreleased SequenceContext object references a SequenceFile object. The following top-level objects were not released: Executions [1 object(s) not released] Type Definitions [2 object(s) not released] Type Definition #1: Name: CommonResults Type Definition #2: Name: Error PropertyObjects [4 object(s) not released] PropertyObject #1: Type: Obj PropertyObject #2: Type: Array of Containers PropertyObject #3: Type: Array of Containers PropertyObject #4: Type: Array of Containers And the following uncategorized objects: UIMessage (TEMessage) UIMessage (TEMessage) Report EditArgs

 I already tried a couple of things:

- introducing the sequential process model in the mix

- experimenting with various combinations of execution.Release(); seqfile.Release(); and teapi.Release();

- implementing the steps in the help topic "Shutting Down the Engine" (although the first bullet point of the second pass is a bit of a mystery to me)

 

However I did not have success yet. Does anyone understand what exactly is still unreleased in my rather simple example?

I am guessing it is "the execution", but was under the impression that ReleaseSequenceFileEx is actually the way to release that.

0 Kudos
Message 1 of 5
(5,343 Views)

Hi Michael,

 

did you check this post?

 

Release a SequenceFile in C#

http://forums.ni.com/t5/NI-TestStand/Release-a-SequenceFile-in-C/m-p/2801794

 

This could be interesting as well:

 

Run TestStand Sequence Silently in C#

https://decibel.ni.com/content/docs/DOC-29585

 

Maybe this helps

0 Kudos
Message 2 of 5
(5,314 Views)

Hello Gregor,

Thanks for your reply. I did in fact read those threads before and read them again after your suggestion, but unfortunately could still not put the info conveyed there to use. There are certain differences in the way C# and C++ handle garbage collection which seems to be the key to my problem. But I really can't tell for sure as I have no clue about C# and am not the greatest expert in C++ either.

Anyway, for now I did manage to seemingly shut down TestStand without creating unreleased references utilizing the built-in destructor of the  TS::IEnginePtr class. I am not entirely convinced this is a robust way to do it because it never explicitly calls "shutdown(true);" but it seems to work in my case. For future web or forum searches leading to this thread I condensed the code to a minimal example:

 

Spoiler
// This is the .cpp file of a MS Visual C++ 2010 win32 console application

#include "stdafx.h"
#import "teapi.dll"

TS::IEnginePtr teapi;

int WaitForUIMessage(int messageid)
{
	TS::UIMessagePtr uimsg;
	int uimsgid;
	bool messagereceived = false;

	while( messagereceived == false )
	{
		uimsg = teapi->GetUIMessage();
		if(uimsg)
		{
			uimsgid = uimsg->Event;
			uimsg = NULL;
			if (uimsgid == messageid)
				messagereceived = true;
		}
	}
	return uimsgid;
}

int _tmain(int argc, _TCHAR* argv[])
{
	TS::SequenceFilePtr seqfile;
	TS::SequenceFilePtr modelfile;
	TS::ExecutionPtr execution;
	_bstr_t entrypoint = "Single Pass";
	_bstr_t sequencepath = "D:\\Test Data\\Trivial TestStand Sequence.seq";
	BSTR unused = L"";

	// Basic initialization steps:
	CoInitialize(NULL);							// initialize COM
    teapi.CreateInstance(__uuidof(TS::Engine));	// initialize TestStand API
	teapi->UIMessagePollingEnabled = VARIANT_TRUE;

	// Aquire references and start execution:
	seqfile = teapi->GetSequenceFileEx(sequencepath,0,TS::ConflictHandler_Error);
	modelfile = teapi->GetStationModelSequenceFile(&unused);
	execution = teapi->NewExecution(seqfile,entrypoint,modelfile,VARIANT_FALSE,0);

	WaitForUIMessage(8);	// UI Message 8 = Execution finished
	
	// Release used References:
    teapi->ReleaseSequenceFileEx(seqfile,0);
	teapi->ReleaseSequenceFileEx(modelfile,0);
	execution = NULL;
	seqfile = NULL;
	modelfile = NULL;
	
    teapi->ShutDown(false);
	WaitForUIMessage(9);	// UI Message 9 = Shutdown complete

	// Call LoginLogout Frontend Callback:
	TS::PropertyObjectPtr logoutparam;
	logoutparam = teapi->NewPropertyObject(TS::PropValType_Container,false,"",0);
	logoutparam->SetValBoolean("logoutOnly", TS::PropOption_InsertIfMissing, true);
	logoutparam->SetValBoolean("isInitialLogin", TS::PropOption_InsertIfMissing, false);
	teapi->CallFrontEndCallbackEx("LoginLogout",logoutparam,TS::ConflictHandler_Error,0);
	logoutparam = NULL;
	WaitForUIMessage(8);	// UI Message 8 = Execution finished

	// Set the engine pointer to NULL and leave the shutdown to the destructor of TS::IEnginePtr
	teapi = NULL;

	return 0;
}

 

 

regards,

Michael

0 Kudos
Message 3 of 5
(5,280 Views)

The following explains how to shutdown the engine:

 

http://zone.ni.com/reference/en-XX/help/370052M-01/tsapiref/infotopics/app_shutting_down_the_engine/

 

Hope this helps,

-Doug

0 Kudos
Message 4 of 5
(5,202 Views)

Hello Micheal,

 

I was trying out your code and its always throwing exception, after the engine instance is created and I debugged  found out the the value at teapi is null. Exception message is shown below

 

exception.png

 

I am new to c++ and still learning. Do you have any suggestion or idea??

 

Thank You!

Regards,

Rajesh

 

 

Rajesh Raghavan Nair

Certified LabVIEW Architect
Certified Teststand Architect
0 Kudos
Message 5 of 5
(3,245 Views)