05-23-2011 10:48 AM
Hello,
I have created a little C# project to acquire (with NI-DAQmx) and display (with MeasurementStudio) signals : it works well like that.
But when I call (at the beginning of my program) an home made DLL (in C++) which initializes COM in ApartmentThreaded mode (it calls CoInitialize()), there is no acquisition from NI-DAQmx : the acquisition callback is not called.
Now, if I change COM initialization mode to Multithreaded (calling CoInitializeEx(NULL,COINIT_MULTITHREADED)) in my DLL, the acquisition works.
But I would like to keep ApartmentThreaded mode...
I don't understand why it doesn't work when my DLL is in ApartmentThreaded mode and why it works in Multithreaded mode because C# also initializes COM in ApartmentThreaded mode (STA) by default, using the instruction [STAThread].
Do you have a solution?
Thank you in advance,
RVFR.
05-24-2011 04:01 AM
Note about versions:
- the acquisition project in written in C# with VisualStudio 2005,
- NI-DAQmx is v9.2.2,
- and my DLL is written with C++ Builder 2006.
RVFR.
05-31-2011 03:58 AM
Hello RVFR,
Thank you for posting on National Instruments forum,
First, when you try to work in ApartmentThreaded, do you receive specific error messages?
The reason you could receive errors or not being able to acquire when you call a DLL from your C# project could be related to how VS coinitializes the thread in which the DLL runs. There are two ways to coinitialize a thread -- single-threaded and multithreaded. Probably VS threads are coinitialized as multithreaded. Therefore, code that requires a single-threaded apartment thread might generate errors when you call it. You must use a single-threaded apartment thread for any code that uses an ActiveX container. For example, you must place the Windows Media Player control in an ActiveX container. Therefore, you should call it on a single-threaded apartment thread. After you coinitialize a thread to one threading model, you cannot coinitialize it to the other threading model.
To work around this issue, create a wrapper function that calls your code on a single-threaded apartment thread. The DLL wrapper should create a dummy function in a new thread coinitialized to single-threaded. Add the code required to run a single-threaded apartment thread inside the dummy function. The following code outlines an example DLL wrapper:
Be sure to add the file <MeasurementStudio>\sdk\libole32.lib\
file to your project.
#include <cviauto.h>
#include <userint.h>
#include <cvirte.h>
#include "toolbox.h"
#include <objbase.h>
#include <windows.h>
#include <winbase.h>
// Include the header file for your server
// Function prototypes
DWORD WINAPI myThreadFunc(LPVOID lpParameter);
// Global error string variable
static char errorString[1024];
// This function will be called from TestStand
int __declspec(dllexport) __stdcall Wrapper(void)
{
int error = 0;
LPVOID lpParameter = NULL; // thread argument
LPDWORD lpThreadId = 0; // thread identifier
HANDLE threadHndl = 0;
//Function called on a separate thread coinitialized as
//apartment threaded
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 (threadHndl)
CloseHandle(threadHndl);
if (error<0)
MessagePopup ("error occurred", "");
return error;
}
DWORD WINAPI myThreadFunc(LPVOID lpParameter)
{
int error = 0;
ERRORINFO errorInfo;
// Call to CoInitialize - Can either be COINIT_MULTITHREADED
// or COINIT_APARTMENTTHREADED
errChk(CoInitializeEx(NULL, COINIT_APARTMENTTHREADED));
// ADD YOUR CODE HERE - Add the code that is required to run
// on a single threaded apartment thread
CoUninitialize();
Error:
// free all resources
if (error<0)
{
CA_GetAutomationErrorString (error, errorString, 1024);
MessagePopup ("error occurred", errorString);
}
return error;
}
Sincerely,
Romain D.
Romain DUVAL || RF & Semiconductor Staff System Engineer || CLA || CTA
National Instruments France