LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Return array data from running DLL to Labview

Solved!
Go to solution

redblue wrote:
Unfortunately it seems that it is not enough for me, because i couldn't get to work it:(...Right now I have solved this problem with sending string from dll and converting it into array in LV, but that doesn't seem to be correct solution.

Then you need to tell us in more detail what you try to do. At least my telepathic capabilities are largely undeveloped.

 

Rolf Kalbermatter
My Blog
0 Kudos
Message 11 of 26
(4,063 Views)

Hi there Rolf and Mario,

 

Since my first post, I have stumbled upon a bunch more forum threads, etc. on this topic (how come I couldn't find them earlier?!).

 

In any case, a couple of notes:

1. In answer to my own question about disposing of the data handles after calling PostLVUserEvent() - Indeed, it seems one should call DSDisposeHandle() in each iteration to avoid the data piling up in memory.  Seems to work fine.

 

2.  If you just want to pass a single string, there is a complete example from NI: http://zone.ni.com/devzone/cda/epd/p/id/1480

The C++ source code and VI are both there (VI in the .llb ... there's a NI forum thread where one person didn't know about llb files...http://forums.ni.com/ni/board/message?board.id=170&message.id=444403 - whoops).

Extending this to an array of strings should be fairly self-evident by combining the code I posted earlier with the string example.

 

3. I terminate the DLL using a static StopFlag variable in the code, adding another exported Stop function to change this value, and use Reentrant calling LV - precisely what is described here: http://lavag.org/topic/2142-stopping-a-custom-dll-from-labview/. 

The Stop function is called in the terminate case of the LV event structure.

 

4.  I suspect that it is not a good idea to copy, paste and modify an Event Structure from one VI into another.  I did this at first, and had some very scary "behind the scenes" problems with the resulting VIs.  No problems if I created a new Event Structure in the VI (maybe I missed some obscure stuff in the Ev. Struct. configuration...) 

 

 

Nevertheless, I am still having problems right now passing a simple cluster (with two single-precision scalars)!  Please could someone tell me what is faulty with the following:

 

 //--------------------------

#include <windows.h>
#include <extcode.h>
#include "LVevent1.h"


// Cluster with 2 scalars floats
typedef struct {
    float    A;            // Dimensions of array
    float    B;            // Array
} clustA, *clustAP,**clustAH;

// Send cluster data
DEXP int LVeventCluster(LVUserEventRef *msg, DWORD msWait, int Nevents)
{
    int iev;
    clustAH clusterH;
    MgErr evErr;

    iev=0;
    do {
        Sleep(msWait);
        clusterH=(clustAH)DSNewHandle(2*sizeof(float));

        (*clusterH)->A = float(iev);
        (*clusterH)->B = float(iev+1);
       
        evErr = PostLVUserEvent(*msg,(void *)&clusterH);
        DSDisposeHandle(clusterH);
        ++iev;
    } while (iev<Nevents);

    return 1;
}

//-----------------------------------

 

 

The prototype in LV is a cluster of two singles.  The data returned are some wild values, and there is some crashing....

I searched a long time (web, LV manuals), but didn't find a concrete example for this.

 

 

Regards, MT

0 Kudos
Message 12 of 26
(4,058 Views)

LabVIEW does not use handles to store clusters. Instead you should allocate a pointer using the function DSNewPtr() or DSNewPClr() and use your clustAP datatype instead of clustAH as event data.

 

You even should be able to create that data structure simply on the stack since PostLVUserEvent() seems to copy that data anyhow.

Message Edited by rolfk on 10-26-2009 11:58 AM
Rolf Kalbermatter
My Blog
0 Kudos
Message 13 of 26
(4,056 Views)

Hi again,

 

I forgot to mention that I am working with LV 8.2, WinXP pro 32-bit, Visual C++ Express 2008 and have set the compiler structure byte alignment to 1 (default also doesn't work).

 

Cheers, Mark

 

0 Kudos
Message 14 of 26
(4,054 Views)
Solution
Accepted by topic author nz_mark

Dear Rolf  - thanks so much!

Plus a 4 minute response time can only be described as outstanding.

So, I got the cluster to work with pointers, as you said.  Then I took a few deep breaths and extended it to an example sending a cluster with a scalar and a 1D array (I'm not a programmer by trade).

The code is as follows (in case anyone ever wants it), and seems to work fine:

 

 

//--------------------------------------

#include <windows.h>
#include <extcode.h>
#include "LVevent1.h"

// 1D float array
typedef struct {
    int32    length;            // Length of array
    float    data[1];        // Array
} arrf1D, *arrf1DP, **arrf1DH;

// Cluster with a scalar float and handle to a 1D float array
typedef struct {
    float    scalar;            // Dimensions of array
    arrf1DH    arrHdl;                // Array
} clustB, *clustBP,**clustBH;

// Send cluster data (*clustB)
// 1 scalar floats and 1 1D array
DEXP int LVeventsCluster(LVUserEventRef *msg, int Nr, DWORD msWait, int Nevents)
{
    int iev;
    int ii;
    clustBP clusterP;
    MgErr evErr;

    iev=0;
    do {
        Sleep(msWait);
        // Allocate cluster pointer
        clusterP=(clustBP)DSNewPtr(sizeof(float)+sizeof(arrf1DH));
           
        // Allocate 1D array handle
        clusterP->arrHdl=(arrf1DH)DSNewHandle(sizeof(int32)+Nr*sizeof(float));
   
        // Set scalar value   
        clusterP->scalar = float(iev);
       
        // Set 1D array length field
        (*(clusterP->arrHdl))->length = Nr;
        // Fill 1D array
        for (ii=0;ii<Nr;ii++) {
            (*(clusterP->arrHdl))->data[ii] = float(ii+iev);
        }
       
        // Send cluster via event
        evErr = PostLVUserEvent(*msg,(void *)clusterP);

        // Clear array handle and cluster pointer
        DSDisposeHandle(clusterP->arrHdl);
        DSDisposePtr(clusterP);

        ++iev;
    } while (iev<Nevents);

    return 1;
}

//--------------------------------------

 

I don't know if disposing the 1D array handle is necessary, but it seems like good style... if anyone has any comments on how to improve this, I would be grateful.

 

So, now I can return to my project! (high speed CCD acquisition, data pre-processing in C DLL returning averaged downsampled frames from time to time to LV front-end)

 

 

0 Kudos
Message 15 of 26
(4,048 Views)

Hi, all.

 

Mark, I think I have a similar problem. I posted it yesterday (link).

 

Do you think your solution could help me?

 

Thanks,

Francisco.

0 Kudos
Message 16 of 26
(3,968 Views)

Dear Francisco, 

 

For sending data to Labview from the running DLL, the stuff in this post (which is just standard Labview external code with Rolf telling me how to do it properly!) is applicable.

 

Concerning passing from LV to your running DLL, I would follow up the replies in your post.

 

As mentioned earlier in this thread, I terminate my running DLL from Labview by using a global Stop variable in the DLL code and call a second function in the DLL (reentrant...) to set this flag and terminate the loop in the first function.  In principle, you could also declare a global pointer to array data in the code, and send the array data in via a second DLL function.

 

However, reading the comments from the experts in your post, this might not be a very stable approach, unless you use semaphores or events to prevent both DLL functions reading and writing simultaneously.  Maybe one day my Stop-flag code will crash...!

 

Regards, Mark

0 Kudos
Message 17 of 26
(3,960 Views)

nz_mark wrote:

Dear Francisco, 

 

However, reading the comments from the experts in your post, this might not be a very stable approach, unless you use semaphores or events to prevent both DLL functions reading and writing simultaneously.  Maybe one day my Stop-flag code will crash...!

 

Regards, Mark


You should be fine with a simple boolean flag. The operation to set a boolean variable is atomic. A different thread reading it can only either see it true or false but there does not exist an intermediate not true and not false state here. If it doesn't read the quit state in this iteration it will simply see it in the next.

 

Typically problems arise when you have either multiple read-modify-write cycles from multiple locations (think of a variable that gets incremented/decremented from more than one place as an example),or in the case of complex variables such as strings/arrays and cluster, where the reader could read part of a still old value and another part being already modified (which could give inconsistent and invalid information).

 

As long as you do deal with integer skalars (booleans are in fact also just integers as far as the C compiler is concerned) and can gurantee that you always only write from one location to that variable (but you can read it from several other places) you would not have to be concerned about possible race conditions and crashes.

Message Edited by rolfk on 11-25-2009 07:37 PM
Rolf Kalbermatter
My Blog
0 Kudos
Message 18 of 26
(3,953 Views)

Hi, nz_mark.

 

I tried your code with simple 1D array and it's works fine.

 

But code with cluster is crashed. Which LV prototype you are using?

 

I need to pass mixed cluster (few arrays with different types) to LV by using PostLVUserEvent().

Can you help me?

 

 

 

0 Kudos
Message 19 of 26
(3,838 Views)

staslast wrote:

Hi, nz_mark.

 

I tried your code with simple 1D array and it's works fine.

 

But code with cluster is crashed. Which LV prototype you are using?

 

I need to pass mixed cluster (few arrays with different types) to LV by using PostLVUserEvent().

Can you help me?

 

 

 


Post what you have so far and we can look at it

Rolf Kalbermatter
My Blog
0 Kudos
Message 20 of 26
(3,820 Views)