08-21-2009 05:21 PM
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
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
Solved! Go to Solution.
08-24-2009 10:27 AM - edited 08-24-2009 10:35 AM
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
08-24-2009 12:57 PM
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
08-24-2009 02:24 PM
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
08-24-2009 04:41 PM - edited 08-24-2009 04:51 PM
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
08-25-2009 01:51 AM
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
08-25-2009 11:12 AM
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
08-25-2009 12:47 PM
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