LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Accessing the DataSocket only using nids.dll

Solved!
Go to solution

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

 

0 Kudos
Message 1 of 14
(5,254 Views)

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!

Best regards
chris

CL(A)Dly bending G-Force with LabVIEW

famous last words: "oh my god, it is full of stars!"
0 Kudos
Message 2 of 14
(5,240 Views)

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 

0 Kudos
Message 3 of 14
(5,235 Views)

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?

Best regards
chris

CL(A)Dly bending G-Force with LabVIEW

famous last words: "oh my god, it is full of stars!"
Message 4 of 14
(5,230 Views)

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 

0 Kudos
Message 5 of 14
(5,207 Views)

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.

Best regards
chris

CL(A)Dly bending G-Force with LabVIEW

famous last words: "oh my god, it is full of stars!"
0 Kudos
Message 6 of 14
(5,205 Views)

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 

 

0 Kudos
Message 7 of 14
(5,184 Views)

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.

 

0 Kudos
Message 8 of 14
(5,179 Views)

Hello candidus,

 

do you have some example code on what messages are to be processed ? Or some description/documentation ?

 

Best regards

 Peter 

0 Kudos
Message 9 of 14
(5,163 Views)
Solution
Accepted by topic author PEESPE

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;
}
 

Message Edited by candidus on 08-05-2009 03:54 AM
Message 10 of 14
(5,145 Views)