NI TestStand

cancel
Showing results for 
Search instead for 
Did you mean: 

Different results using DLL from TS or CVI

I am trying to access som COM components using teststand... These components don't have the required interface for TS, so I created an activeX controller insrument driver using CVI... I then generated a TS compatible DLL in two ways... #1 Created a dll with type library - TS can see the parameters ok using the DLL adapter...
#2 created an activex server - TS can use the activex adapter to access the functions & parameters...

The problem that I have is that using either method described above, the results are the same... The calls to the COM components basically work, but not fully... most of the methods appear to work ok, but some produce errors (0x80010105). If I use CVI and call the methods using the same DLL as
in #1 above, then everything works fine.
It looks like my problem is something to do with the interface between TS and the DLL, although I can't figure out exactly what the problem is. If I debug the code from TS, the variables seem comparable to those when run from CVI...
Any suggestions will be gratefully received
0 Kudos
Message 1 of 3
(3,589 Views)
Jbarlow,

I have seen this inconsistency before (i.e., it works in my development environment but it fails when called from TestStand) and even though it might be unrelated, I can offer some insight.

ActiveX defines two main concurrency models for which you can initialize a thread: apartment-threaded and multi-threaded (free-threaded). Before you can use ActiveX in a thread, you must initialize the thread to use one of these models.

TestStand initializes each execution thread to use the multi-threaded concurrency model. Any subsequence calls to initialize OLE to the apartment-threaded model within a step module will fail.

Make sure the COM components you are accessing are not trying to initialize the OLE threading model to apartment-threaded. Or if they are, to error-chec
k for the possibility of these calls failing and take correct action.

Otherwise, the only workaround known to guarantee that calls to your COM components occur in an apartment-initialized thread is to create a worker thread in which you funnel all COM calls. After you create the thread, you must initialize the thread to use the apartment-threaded model.

On another note, I found the error code to be related to the COM Server/Client connection. Here is the link in the Microsoft web site:

http://support.microsoft.com/support/kb/articles/Q289/7/37.ASP

Regards,

Azucena Perez
National Instruments
0 Kudos
Message 2 of 3
(3,588 Views)
You say that when you call your code from CVI it works. In testing your code outside of TestStand, you may want to do so in a manner that most simulates calling your code from TestStand. As Azucena implied, this means that within your standalone application you should execute your functions on a separate thread that is coinitialized as multithreaded. It could be that your code will not execute on a thread that is coinitialized as multithreaded. I have included some test VC and CVI code that I used at some point to simulate TestStand calling a DLL. Excuse any errors or non-standard usage.

If you get the same error I would then recommend you comment out the CoinitializeEX function. This will tell you whether your code is trying to coinitialize has something other than multithreaded mode.

Hope this helps.

(You will have to fix the wrapping of the code.)


===================
VC Code:

#include "stdafx.h"
#include
#include
#import "C:\\TEMP\\YourServer.dll" no_implementation

int main(int argc, char* argv[])
{
HANDLE hThread = NULL;
DWORD error =0;
DWORD threadId;
DWORD tmpExitCode = 0;
LPLONG lpExitCode;

//Function called in the main thread of the application is NOT the manner
in which TS calls DLL functions. In your
//current application it sounds like this is working.
tmpExitCode = myThreadFunc(NULL);

//Function called on a separate thread coinitialized as multithreaded is
how TS calls DLL functions. This may not
//work with your current application.
hThread = CreateThread (0, 0, myThreadFunc, NULL, 0, &threadId);
if (hThread)
{
WaitForSingleObject (hThread, INFINITE);
GetExitCodeThread(hThread, &exitCode);
CloseHandle (hThread);
}
lpExitCode = (long) tmpExitCode;
return *lpExitCode;
}


DWORD WINAPI myThreadFunc(LPVOID lpParameter)
{
HRESULT __result;
IYourServerPtr *mycallmgr;
CLSID clsid = __uuidof(YourServer);
IID iid = __uuidof(IYourServer);

CoInitializeEx(NULL, COINIT_MULTITHREADED);

//YOUR CODE SUCH AS:

__result = CoCreateInstance(
clsid,
NULL,
CLSCTX_SERVER ,
iid,
(void **) &mycallmgr);
Initialize ();
Test ();
Cleanup();

CoUninitialize();
return __result;
}
======================

CVI Code:

#include
#include "MyServer.h"
#include
#include
#include "toolbox.h"
#include
#include
#include


DWORD WINAPI myThreadFunc(LPVOID lpParameter);
static CAObjHandle MyServer=0;
static char errorString[1024];


int main (int argc, char *argv[])
{
int error = 0;


LPVOID lpParameter; // thread argument
LPDWORD lpThreadId; // thread identifier
HANDLE threadHndl;

if (InitCVIRTE (0, argv, 0) == 0)
return -1; /* out of memory */



//Function called in the main thread of the application
//is NOT the manner in which TS calls DLL functions.
//In your current application it sounds like this is working.
errChk(myThreadFunc(NULL));

//Function called on a separate thread coinitialized as
//multithreaded is how TS calls DLL functions. This may not
//work with your current application.
threadHndl=CreateThread(
NULL, // SD
0, // initial stack size
myThreadFunc, // thread function
lpParameter, // thread argument
0, // creation option
NULL // thread identifier
);
if (threadHndl)

errChk(WaitForSingleObject (threadHndl, INFINITE));

Error:
// free all resources
if (error<0)
MessagePopup ("error occurred", "");

return error;
}


DWORD WINAPI myThreadFunc(LPVOID lpParameter){
int error = 0;
ERRORINFO errorInfo;

errChk( CoInitializeEx(NULL, COINIT_MULTITHREADED));

//Create my server object
errChk(MyServerLib_NewIMyServer (NULL,1, LOCALE_NEUTRAL, 0,
&MyServer));
CoUninitialize( );

Error:
// free all resources
CA_DiscardObjHandle(MyServer);
if (error<0)
CA_GetAutomationErrorString (error, errorString, 1024);
MessagePopup ("error occurred", errorString);

return error;
}
0 Kudos
Message 3 of 3
(3,588 Views)