LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Passing a 1D array from old version of Labview 8.5 to VB .NET (using Visual Studio 2015)

Hi all-

 

This is an extension of a solved problem, in trying to pass information from Labview to VB .NET via a DLL:

 

https://forums.ni.com/t5/LabVIEW/Recent-xamples-for-creating-DLL-for-VS-NET-Community-edition/m-p/37...

 

The new problem is passing an array back from the DLL to the .NET program.

 

This problem was originally mentioned and theoretically solved years ago:

 

https://forums.ni.com/t5/LabVIEW/Trying-to-use-a-Labview-dll-in-Vb-NET-2003/m-p/156020

 

Again, my colleague is using  LV 8.5.   So, they were able to download the .VI from above solution, and create a DLL.  I'm able to load it up in my program, however, when I pass  in the array (as defined in the code below), it seems to get squashed by the DLL somehow.  If you break the program at the dSimplePass() call, the mdblArray shows up as 'Nothing' instead of the Double array. 

 

So, something isn't quite right.

 

A bit more digging; the VS command line tool 'dumpbin' (dumpbin datapass.dll /exports) shows that the DataPassDll function is exported, so we know it exists.

 

On the VI side, my colleague sent me a screen shot of the DLL creation procedure (attached).

 

If I change the mLen to be called ByRef instead of ByVal, the array isn't vaporized(!) (but has only length 0), and the value becomes something bizarre (a huge value), so my gut tells me something is getting stomped on somehow in memoryland. 

 

Now, in a fit of what-the-hell, (changing the array call to be ByVal (which is silly, because it has to be passed back))... it WORKS!  So, what is going on here?  If I'm passing an array in ByVal, shouldn't this be an issue, or am I getting something obvious wrong?

 

If I define the function (no byRef or ByVal):

 

Declare Sub dSimplePass Lib "datapass.dll" Alias "DataPassDll" (dIn As Double, dOut() As Double, mLen As Long)

 

... it works fine as well!

 

 

  Declare Sub dSimplePass Lib "datapass.dll" Alias "DataPassDll" (ByVal dIn As Double, ByRef dOut() As Double, ByVal mLen As Long)
    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        Try
            Dim mDbl As Double
            Dim mdblArray(5) As Double
            Dim mLen As Long
            mLen = 5
            mDbl = 1.5

            Dim i As Integer
            Dim sMessage As String

            For i = 0 To mLen - 1
                mdblArray(i) = i * 100
            Next

            sMessage = ""
            sMessage = "Input:" + vbCrLf
            sMessage = "mDbl = " & mDbl.ToString + vbCrLf
            sMessage = "mLen = " & mLen.ToString + vbCrLf
            For i = 0 To mLen - 1
                sMessage = sMessage & i.ToString & " " & mdblArray(i).ToString & vbCrLf
            Next

            MsgBox(sMessage)

            ' Call DLL
            dSimplePass(mDbl, mdblArray, mLen)

            sMessage = ""
            sMessage = "Output:" + vbCrLf
            sMessage = "mDbl = " & mDbl.ToString + vbCrLf
            sMessage = "mLen = " & mLen.ToString + vbCrLf
            For i = 1 To mLen
                sMessage = sMessage & i.ToString & " " & mdblArray(i).ToString & vbCrLf
            Next

            MsgBox(sMessage)
Catch ex As Exception MsgBox("Error = " & ex.Message) End Try End Sub

 

 

 

 

 

 

0 Kudos
Message 1 of 5
(3,193 Views)

Your problem is likely because of the calling convention. From the attached image it would appear that your function is declared as cdecl. But the Visual Basic Declare syntax by default assumes stdcall. I'm not sure it is possible to make the Declare use cdecl instead. The recommended .Net way of doing things nowadays is to use the P/Invoke method with the DLLImport statement.

 

<DllImport("<dllname>", EntryPoint:="<actual exported function name>", CallingConvention:=CallingConvention.Cdecl)>
Public Shared Function YourVBFunctionName(ByVal a As Integer, ByVal b As Integer) As Integer
End Function
Rolf Kalbermatter  My Blog
DEMO, Electronic and Mechanical Support department, room 36.LB00.390
0 Kudos
Message 2 of 5
(3,150 Views)

Interesting; trying that convention:

 

    <DllImport("..\LabVIEW\DataPass.dll", CallingConvention:=CallingConvention.Cdecl, EntryPoint:="DataPassDll")> _
    Private Shared Sub dSimplePass(ByVal a_input As Double, ByRef a_output() As Double, ByVal a_length As Long)
    End Sub

... gives me an error; changing the 'ByRef' to 'ByVal' for the a_output() array works again!

 

0 Kudos
Message 3 of 5
(3,143 Views)

Well arrays are reference types so even if you specify ByVal, VB.Net will put the pointer reference to the array on the stack. What probably happens when you specify ByRef for an Array Parameter is that VB .Net at least in the PInvoke interface will pass a reference to the pointer reference instead. The function expecting an array pointer instead will happily update what it thinks is an array but overwriting the pointer reference for the Visual Basic array instead. From here on anything can happen from a crash, to a eaten harddisk or a nuclear explosion Smiley Very Happy

Rolf Kalbermatter  My Blog
DEMO, Electronic and Mechanical Support department, room 36.LB00.390
0 Kudos
Message 4 of 5
(3,140 Views)

Basically what happens here is some kind of symbol overload. ByVal may have the effect you believe it should have when it is applied to a parameter to a function implemented in VB .Net. This is done by VB when compiling the function itself, where it probably creates a local copy of an array passed in as ByVal, whenever the function attempts to update the array. The parameter is still passed as an array pointer. For ByRef parameters the parameter is really passed as a pointer to an array pointer and the VB function does not make any attempts to create a local copy of the array for overwriting inside the function.

 

However in C you have nothing like a ByVal array or string (well sort of by declaring the parameter as const, then any attempt inside the function to write to that array parameter will be flagged during compilation as illegal). The DLL interface and therefore what LabVIEW creates when creating a DLL is however purely based on C syntax, so a function is free to modify the contents of the array passed in as a pointer, but not the pointer itself as that will not get passed back to the caller.

If a function is meant to modify the pointer itself (by re/allocating the array or freeing it) the parameter needs to be passed as a reference to the pointer (and the caller needs to be fully aware and prepared for that too).

Rolf Kalbermatter  My Blog
DEMO, Electronic and Mechanical Support department, room 36.LB00.390
0 Kudos
Message 5 of 5
(3,130 Views)