10-26-2009 05:08 AM
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.
10-26-2009 05:53 AM
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
10-26-2009 05:57 AM - edited 10-26-2009 05:58 AM
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.
10-26-2009 06:01 AM
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
10-26-2009 07:01 AM
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)
11-25-2009 10:21 AM
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.
11-25-2009 10:57 AM
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
11-25-2009 12:35 PM - edited 11-25-2009 12:37 PM
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.
12-08-2009 09:34 AM
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?
12-09-2009 01:01 AM
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