LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

output arrays from .NET assemblies are not being dereferenced

In order to use LabView7.1 with a .NET assembly, we had to dereference the output parameters of each method by creating .NET support classes. While this solution allowed us to use .NET assemblies with LabView7.1, it also created a lot of code clutter in both the LabView and the .NET assembly code. Anyways, we continued with our .NET development in hopes that this problem would be resolved in later versions of LabView. Our hopes came partially true... LabView8 does fix the output parameter problem for all the primitive data types (yahoo, thanks guys!), but it fell sort when it came to outputting arrays. I still have to add extra code to dereference output arrays. Was this bug missed or is this the way arrays are handled when using .NET assemblies?
 
This problem does not occur in TestStand3.1.
0 Kudos
Message 1 of 9
(3,632 Views)
 
Yes, I'm afraid it's my fault - I was a bit over zealous when fixing the problems in 7.x regarding mapping .NET data types to LabVIEW types. The code in 8.0 basically said that if it's an input parameter, it's an input only on the invoke node...forgetting the subtle difference in data flow and .NET...*sigh*. My apologies.
 
The good news is that it's been fixed in the 8.0.1 patch that you can download here: [link removed]
 
This patch does require a mass compile, so I'd recommend installing it at the end of the day, launching LV and telling it to mass compile when it asks...then go home. The mass compile takes a few hours.
0 Kudos
Message 2 of 9
(3,626 Views)
Well, version 8.0.1 changed things, but not to what I was expecting. First, the input array is now shown as an input/output where it previously was shown as only an input (and it should only be shown as an input). Secondly, I never saw any difference in handling the output array (it still needs to be dereferenced). Is there a 8.0.1b version?
0 Kudos
Message 3 of 9
(3,622 Views)
Oops, wait a minute... it looks like I never mass compiled (all the labview dependant vi's).  Sorry.
0 Kudos
Message 4 of 9
(3,620 Views)

What's up doc?

I did a mass compile and I got numerous compilation errors (see attachment).

Anyways, do any of these errors effect the .NET development. If not, I am still getting the same unexpected results that I got before the mass compile (i.e. input arrays show up as both in/out and output arrays still need to be dereferenced).

Please advise me as to what I need to do in order to fix these problems.

Thanks,

Bugs

0 Kudos
Message 5 of 9
(3,614 Views)
As far as the mass compile, the first set of VI's aren't a problem - they're CIN examples that don't have the code modules loaded. I don't know what is going on with the DMM VI's...you might need to repost on that one, or contact support. I'd check to see if they load and compile. However, none of those have anything to do with .NET.

As far as the other part, now I'm getting confused. Based on what you're saying, let me try summarize...

void foo(int[] data)

In 8.0, this shows up as an input only for the invoke node. The problem here is that, since the array is copied from LV to .NET data types, any modification done to the array "data" is lost. So, in 8.0.1, this has both an input and output terminal, so that the .NET array "data" is copied back out into LV data. This allows you to handle the modifications (such as for int Read(char[] buffer))

void foo(out int[] data)

In this case, the data is passed by reference, so what you should see is an output only terminal on the invoke node, with the data type being a reference to the array (.NET refnum). The reason it's a refnum is that it's a reference to the data, not the data itself (that is what the ref or out keywords mean in C#). However, due to feedback I've already received, we're changing that in the next release of LabVIEW (code named Europa), so that it should appear as an output only terminal which returns a LV data of int32s.

Does that clarify things? If not, please let me know where the misunderstanding is.

Brian
0 Kudos
Message 6 of 9
(3,612 Views)

Hi Brian,

I have enclosed a Microsoft Word document capturing how we think LabView should handle parameter passing.

Your comment:

void foo(int[] data)

In 8.0, this shows up as an input only for the invoke node. The problem here is that, since the array is copied from LV to .NET data types, any modification done to the array "data" is lost. So, in 8.0.1, this has both an input and output terminal, so that the .NET array "data" is copied back out into LV data. This allows you to handle the modifications (such as for int Read(char[] buffer))

My response:

If you pass a parameter in by value (i.e void foo(int[] data), then the .NET assembly method should copy the data. Any modifications that the .NET assembly method does to its copy of the data should not modify the data within LV. However, if you pass a parameter in by reference (i.e. int Read(char[]& buffer), then the .NET assembly should be able to modify the "buffer" within LV.

Your comment:

void foo(out int[] data)

In this case, the data is passed by reference, so what you should see is an output only terminal on the invoke node, with the data type being a reference to the array (.NET refnum). The reason it's a refnum is that it's a reference to the data, not the data itself (that is what the ref or out keywords mean in C#). However, due to feedback I've already received, we're changing that in the next release of LabVIEW (code named Europa), so that it should appear as an output only terminal which returns a LV data of int32s.

My response:

Should the prototype be "void foo(out int[]& data)"?  I am with your other users, please dereference your output arrays.

Final comments:

Will the next release still be LabView8.x or LabView9?  We want to use LabView with .NET assemblies, but we need the parameter passing issue resolved.

Thanks for help,

Bugs Bunny

0 Kudos
Message 7 of 9
(3,599 Views)
Good writeup of the current situation. Let me explain why the array issue is the way it is, and hopefully you'll agree with where we are going...

For the case (2a in the document)

void foo(int[] a)

There are two issues to consider. The first is that while the array object is passed in by value, the value is the "pointer" to the array. Thus I can't change which instance the parameter pointers to (at least as far as the caller is concerned), but I am completely free to change the data in the array. The classic example is

int Read(char[] buffer)

In this case, you're going to read into a pre-allocated buffer until either the stream is empty or the buffer is full. If this was an input only terminal on an invoke node, you wouldn't be able to see the results. This leads into two issues...

1. The memory used to hold onto the array in LV and .NET are different, but not only in address. LV is a native app with it's own memory manager. .NET is a garbage-collected system. Thus there is no way for an array in LV and an array in .NET to share memory (assuming LV is the caller, which is the case here). This means we need to do data copies. Given that, we have to copy the data back out of .NET in order for the LV user to see it.

2. LV is a data flow language. This is a very subtle, but a very important distinction. The impact in this case is to realize that there are no variables in LV (ignoring the "added" concept of local and global variable nodes). The wire is a representation of data flowing from one control point to another. Once the data "gets off the wire", it has to get onto another wire to "exist". Thus, as far as LV is concerned, there isn't any difference between an int[] and an int[]&. Internally, we know the difference and do the right thing with .NET, but to the LV code, they are the same. The fact that the callee can't change the size of the array in the first case and can in the second case doesn't matter - LV is always prepared for changes in the data, so the output wire is always the "right size".

Result: The way we handle arrays in 8.0.1 is how we plan to continue handling them

For the case (2b and 2c in the document)

Here we agree - for the same reasons as above, the fact that there is a & doesn't matter to LV. We are fixing that oversight.

To answer the question,

void foo(ref int[] data)
or
void foo(out int[] data)

is the C# syntax. The & notation is for C++ and is also how it's represented internally by the CLR. When I write examples, I often use C# since more people are familiar with that, but when you see it in LV, it's an & because that is what .NET wants to see.

And the Magic 8 Ball Says

I'm afraid that only marketing knows what the next version of LV is called. To be absolutely safe, all I can say is that Europa is the code base we are currently planning to be the next release, and is the one with the dereference fix 🙂

Since I can't say any more than that, I must recommend that you talk to your local sales rep to see what they can tell you about the release and/or the beta.

In case you're curious

Because it's often confused people, let me explain the difference between ref and out (or in C++, the [InAttribute] and the [OutAttribute]). As far as the CLR is concerned, there is no difference - the C++ syntax is the closest to the true form.

void foo(int[]& foo)

That is the same "digital" signature for both cases. Like most attributes in .NET, they are merely decoration stored in the meta data of the assembly and ignored by the CLR during execution. The out or OutAttribute is simply a hint to whomever is interested that any information passed in that argument is ignored. This is important for clients like LV (we don't provide an input) or .NET remoting (it doesn't need to waste network bandwidth sending the starting state across).
Message 8 of 9
(3,596 Views)
Hi Brian,
 
Thanks for the response. I agree with your explanation on case 2a.
 
BTW, the same issue exists when using a C# client.
 
Cheers,
Bugs
0 Kudos
Message 9 of 9
(3,567 Views)