07-31-2009 03:48 AM
Hello,
I have the task to communicate to a program, written in LabView, just by communicating through the data socked, using only the INIDSCtl and ICWData interfaces of nids.dll. The communication in the direction that I send data to the LabView program works, but I have problems receiving the data. The data that are sent are an array of 4 float ( 32 bit floatingpoint) values. I can see in the Data Socket Server Diagnostics that there are really packages sent, but I cannot receive those data.
I am programming this in C++ using MS Visual Studio 6.0. I do not have any other tools ( like Measurement Studio ).
The working code to send just a simple 16 bit integer value is (I removed all error checking for shorter code)
#import "C:\windows\system32\nids.dll" raw_interfaces_only, no_namespace, named_guids
...
HRESULT hr = g_pNIDSCtl.CreateInstance("CWDSLib.CWDataSocket");
...
ComBSTR bstrURL(_T("dstp://localhost/emmenu_to_ts"));
hr = g_pNIDSCtl->put_URL( (bstr_t)bstrURL );
hr = g_pNIDSCtl->put_AccessMode( cwdsWrite );
short b;
hr = g_pNIDSCtl->SyncConnect( 30000, &b );
ICWData *pData = NULL;
hr = g_pNIDSCtl->get_Data( &pData );
CComVariant varStart( (short)1 );
hr = pData->put_Value( varStart );
pData = NULL;
hr = g_pNIDSCtl->Update();
hr = g_pNIDSCtl->Disconnect();
However the code to retrieve the data that is not working is as follows
CComBSTR bstrURL(_T("dstp://localhost/ts_to_emmenu"));
hr = g_pNIDSCtl->put_URL( (bstr_t)bstrURL );
hr = g_pNIDSCtl->put_AccessMode( cwdsRead );
short b;
hr = g_pNIDSCtl->SyncConnect( 30000, &b );
ICWData *pData = NULL;
hr = g_pNIDSCtl->get_Data( &pData );
CComVariant varVal;
hr = g_pNIDSCtl->Update();
hr = pData->get_Value( &varVal );
//
// HERE varVal is always 0, independent of the values in the data socket ? ? ?
//
pData = NULL;
hr = g_pNIDSCtl->Disconnect();
My question: Is it even possible to retrieve an array of 4 floats using only the interfaces of nids.dll and if yes, can someone push me in the right direction or give me some hints.
Thanks in advance
Peter
Solved! Go to Solution.
07-31-2009 05:35 AM
Hi there
Just a wild guess:
In case "dstp://localhost/ts_to_emmenu" is a dynamically created item your write - code has to keep the items object instance in memory until the item is read by the read object instance. Don't call g_pNIDSCtl->Disconnect() until the read - code has finished, otherwise the item will be deleted from the server and created new by the read - code, thus containig no data.
Or create a static item using the dstp server manager!
07-31-2009 07:14 AM
Hi Chris,
I use different URLs to read and write. Thus, the write code should (hopefully) not interfere with the read code. The basic idea is that I send a single value to the LabView program ( like some trigger ) and then it starts sending data independently.
This data I want to access, but I have the feeling that the reading itself is programmed wrong ( e.g. something missing, wrong methods called etc. )
Thanks so far
Peter
07-31-2009 07:46 AM
Oh, i see.
I wrote a little app in C# Express, and it works perfectly well.
I used your code, same methods/propertys in the same order as you did. Run VI\dstp_cs_LV2CS.vi and then \dstp_cs\bin\Release\dstp_cs.exe. Maybe there's something wrong on the LV side?
08-03-2009 09:56 AM
Hello Chris,
I have only LabView7 here so I cannot see your vi program. Also the C# program did not send any output ( just an empty command window, only a few milli seconds before closing some text starting with 'system' appears ).
My question: What data does dstp_cs_LV2CS.vi generate? A simple float (single) value or an array of floats ?
Thanks for your effords so far.
Peter
08-03-2009 10:51 AM
Hi there
attached is the screenshot of the LV app. Make sure you have .NET Framework 2.0 or later installed. Take a look at the .cs source file.
08-04-2009 09:47 AM
Hello Chris,
we created simple LabView test programs. One that only sends a single value to DS ( same as you did it ) and here we are able to read the data from the DS.
But the second LV test program sends an array of 4 values (32bit floating point) and then the reading program failed. The Data method returns a VARIANT set to VT_I4 which is completely wrong and the value is always 0.
My impression is: As soon as an array is involved, reading the DS from an external C++/C# program is no more possible, or at least it must be done completely different, but how ???
If you modify your LV program in a way that it sends an array, are you able to read the data from the DS ?
Best regards
Peter
08-04-2009 10:17 AM
It's possible, I did it some time ago but it's a bit more complicated:
You also need a hidden or messageonly window with its own message pump to process your incoming COM calls.
Create a second thread, don't forget to call CoInitializeEx(), creata a window with a message pump and keep that thread alive until you finished reading.
08-04-2009 12:20 PM
Hello candidus,
do you have some example code on what messages are to be processed ? Or some description/documentation ?
Best regards
Peter
08-05-2009 03:53 AM - edited 08-05-2009 03:54 AM
Hello Peter,
Sorry I mixed some things up... I really needed a window because I wanted to be able to use INIDSCtl.SelectURL() .
But it is unecessary for using DataSocket. The important things are:
1. Call CoInitializeEx() with COINIT_MULTITHREADED parameter.
2. After connecting to server, call INIDSCtl.GetStatus() repeatedly until it returns cwdsConnectionActive.
3. Call INIDSCtl.Update() and read your data.
Here is a quick and dirty example which you can try in conjunction with "DS Writer.vi" example:
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <comip.h>
#include <process.h>
#include <iostream>
#import "nids.dll" no_namespace
int main()
{
HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
{
// Create DataSocket instance.
INIDSCtlPtr ds;
hr = ds.CreateInstance(__uuidof(CWDataSocket));
// Connect to server.
hr = ds->ConnectTo(_bstr_t(L"dstp://localhost/wave"), cwdsRead);
// Wait until connection established.
CWDSStatus status;
while ((status = ds->GetStatus()) == cwdsConnecting)
{
Sleep(100);
}
// Get data.
while ((hr = ds->Update()) == S_OK)
{
if(ds->GetDataUpdated() == VARIANT_TRUE)
{
_variant_t retVal = ds->GetData()->GetValue();
// check the type of the VARIANT. It must be an array of double.
if (V_VT(&retVal) != (VT_ARRAY | VT_R8))
throw _com_error(E_FAIL);
// Unpack array.
SAFEARRAY* psa = V_ARRAY(&retVal);
if (psa == NULL)
throw _com_error (E_POINTER);
// It must have one dimension.
if (psa->cDims != 1)
throw _com_error(E_FAIL);
double HUGEP* vals;
HRESULT hr = S_OK;
if (FAILED (hr = SafeArrayAccessData(psa, (void HUGEP**) &vals)))
throw _com_error (hr);
for (unsigned long i = 0; i < psa->rgsabound[0].cElements; i++)
{
std::cout << vals[i] << std::endl;
}
// Array no longer needed.
if (FAILED (hr = SafeArrayUnaccessData(psa)))
throw _com_error (hr);
}
}
}
CoUninitialize();
return 0;
}