LabWindows/CVI

cancel
Showing results for 
Search instead for 
Did you mean: 

How to return VB.NET data from a CVI dll

Solved!
Go to solution

All,

 

I have some signal processing code written in LabWindows/CVI 8 that needs to be accessed from automation software written in VB.NET 2008.  My first thought is to compile the CVI code into a DLL and call it from VB.NET.

 

So far I can manipulate integers and doubles that are passed by reference between both CVI and VB.

I can also read an array of doubles that is passed to CVI from VB.

I have not been able to return an array/pointer to an array of doubles back to VB from CVI.

 

Here are some simple examples: 

 

Labwindows/CVI code: 

int DLLEXPORT AddDoubleByRef(double a, double b, double* c)
{
    *c = a + b;
    return 1;
}
int DLLEXPORT AddDoubleArray(double* DoubleArray, int N, double* c)
{
    int i;
 
    *c = 0;
    for (i=0; i < N; i++) 
    {
        *c += *(DoubleArray+i);
    }
    return 1;
}

 

VB code: 

<DllImport("DLL_TEST.DLL")> Public Function _

    AddDoubleByRef(ByVal a As Double, ByVal b As Double, ByRef c As Double) As Integer

End Function

 
<DllImport("DLL_TEST.DLL")> Public Function _
    AddDoubleArray(ByVal a() As Double, ByVal N As Integer, ByRef c As Double) As Integer
End Function

 

The problem:

My signal processing code generates 2 arrays of doubles whose length is dependent upon the input arrays.

Since I can not get array data back to VB, my only option is to return 1 element at a time using something like this: 

 

Labwindows/CVI 

double DLLEXPORT IndexArray(int index)

{

    return *(MyDoubleArray + index);

}

 

 

It seems to me that there has got to be a better way to interact with VB.NET.  Any ideas/suggestions?

Is there anyway I can use the CVI .NET library to assist with this task?

 

thanks,

steve 

0 Kudos
Message 1 of 8
(5,733 Views)

We used to see a similar problem in VB6 when passing array data from a CVI dll to a VB6 application.

 

In our case it was string passage to VB from CVI that was the problem.  The string was an array of chars in CVI and unless the receiving string in VB6 had been declared to a specific size, no memory in VB6 was allocated to receive the string.  Apparently the VB6 runtime would only allocate memory for the string upon first reference to it from VB.

 

One solution was to DIM the VB6 string to a specific size, forcing the VB runtime to allocate the memory.  VB6 was then able to receive the array from the CVI dll.

 

And I seem to recall that we wound up declaring the string as "By Val".

 

We also would use what's called a "safe array" to receive arrays of doubles from a DLL into VB6.    If you don't want to hassle through all of this you could simply write the array out to a disk file from CVI and then read it from VB.  CVI has a library call to write arrays of doubles out to a disk file as I recall.  I did resort to this when I didn't want to figure out / remember the safe array technique and timliness wasn't an issue.

 

I don't know if any of this is relevant to vb.net, but the fact of being unable to pass an array from a CVI dll back to a VB application certainly is the same symptom. 

 

Menchar

Message Edited by menchar on 08-24-2009 08:35 AM
0 Kudos
Message 2 of 8
(5,698 Views)

steve,

 

menchar's advice is solid. Please try out his method and post as to whether or not that fixed the problem.

 

Regards,

 

Steven Zittrower

Applications Engineer

National Instruments

http://www.ni.com/support

0 Kudos
Message 3 of 8
(5,689 Views)
Solution
Accepted by topic author the steve

Thanks for the advice- I can now pass data fro the DLL to VB.NET

Here is the code with the magical combination of variable declarations.

 

Labwindows/CVI:

int DLLEXPORT SetArray(double* DoubleArray, int N)
{
    int i;

    for (i=0; i < N; i++)
    {
        *(DoubleArray+i) = i;
    }
    return 1;
}

 

 

VB.NET:

<DllImport("DLL_TEST.DLL")> Public Function _

    SetArray(ByVal DoubleArray() As Double, ByVal N As Integer) As Integer

End Function

 

0 Kudos
Message 4 of 8
(5,679 Views)

Dang I'm good.

 

I think it gets more complicated if you're using a multiple-dimension array - C arrays are always singly dimensioned (a multiple dimension C array is really a singly-dimensioned array of arrays) and "row major" storage but who knows what VB does.

 

Yup, the "By Val" is somewhat counter-intuitive but that's what works.  The "value" in this case is the array address.  In C, everything is passed by value (sometimes the value is a pointer) and an array name is the address of the array.  By Ref gives you the address of the address of the array and you'd wind up with an extra level of de-referencing that you don't need with C.

 

Menchar

Message Edited by menchar on 08-24-2009 02:46 PM
Message Edited by menchar on 08-24-2009 02:51 PM
0 Kudos
Message 5 of 8
(5,673 Views)

Menchar,

 

I was wondering if one can use a variant to pass the array data from CVI dll to VB6. Looking yesterday into this issue, I didn't find a way to generate an fp for the CVI dll, that would  have a variant as an I/O parameter, so I could't create a dll to try this.

I saw that you propose using a safearray, how can this datatype be passed between CVI dll and VB ?

 

Regards

0 Kudos
Message 6 of 8
(5,654 Views)

MiniMe -

 

Well, I wouldn't think I'd try to pass a variant - but it may be possible.  I believe Microsoft says not to pass a variant to a DLL or a struct/record either for that matter.  I imagine you can pass a variant if you want to badly enough, you'd need exact detail as to the internal storage structure of the variant polytype.   A C struct can have padding differences with a VB record.  Having said that, I know people who have passed C structs into VB as records and vice versa.

 

Variants can lead to lots of grief with subtle and non-obvious type conversions that will drive you nuts.   I'll agree that variants are interesting from a computer science point of view, but any polytype (there are other languages that support a polytype, but probably none you've ever heard of) results in all sorts of type inferencing and type coersions that are implementation dependent and very hard to anticipate and you wind up discovering these at run time since the compiler will convert anything to anything.  I'm all for strong typing.

 

As for safe arrays, see this link:  http://msdn.microsoft.com/en-us/library/ms221482.aspx

 

also:

 

http://support.microsoft.com/kb/167668

 

and:

 

http://sandsprite.com/CodeStuff/Writing_A_C_Dll_for_VB.html

 

for how to do it with C++.  I am not morally certain it can be done in C with CVIbut I suspect it can.

 

Safe arrays are used with COM (ActiveX) to pass arrays between COM objects.  VB6 can use COM objects (all VB6 objects are COM objects) so if you were to put the data into a safe array VB6 can get to it.  I do not have all of the details at hand but I know it can be done, at least with a DLL written in C++.

 

Menchar

0 Kudos
Message 7 of 8
(5,637 Views)

My apologies for wandering off topic - I see you asked about VB.net, rather than vb6.

 

Maybe with vb.net the issue of using a C or C++ DLL isn't quite so compelling, since C# is available.

 

But, we've had performance issues with C# so maybe there is a need for C / C++ DLLs to support vb.net similar to the way we use them to support vb6.

 

My experience is strictly with vb6, I'm just now learning a bit about vb/net.

 

menchar

0 Kudos
Message 8 of 8
(5,625 Views)