LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

How to Marshal a .net structure from LabVIEW

Solved!
Go to solution
I am trying to read data from a device via a .net API. The read function has the following interface definition:


uint32 mxfASCBRxSamplingRead ( HMXF_BUFFER buffer,

                                      uint64 flags,
                                      uint64 maxRecCount,
                                      uint64 maxBytesCount,
                                      uint64 * recCount,
                                      uint64 * byteCount,
                                      MXF_ASCB_SAMPREC * rec
                                      )




MXF_ASCB_SAMPREC Struct Reference

 

                                      Data Fields:
                                      uint64 timeTag
                                      uint32 control
                                      uint32 rate
                                      uint32 errorCount
                                      uint32 dataSize
                                      uint16 data [256]




The MXF_ASCB_SAMPREC input of mxfASCBRxSamplingRead is giving me trouble. It is left for the caller of this method to allocate memory for the method to place data into for the caller to subsequently access. When I look at that input to the .net invoke method for MXF_ASCB_SAMPREC, it is a reference of this type: "System.IntPtr, mscorlib". I found that function, but it looks to just convert a pointer to an integer. The vendor has no examples of LabVIEW calling their assembly, and does not know how to interface this method into LabVIEW, but they do know that other customers have managed to support this method. The only documentation they can supply is C#. The applicable portions of the C# example are below.
 
Anyone have an idea of how to connect to this thing? 
 
 
            // allocate buffer
            if (rc == MAXT_SUCCESS)
            {
                rc = mxfRxSamplingBufferAlloc(channel, (UInt64)rxBufferSize, out sampBuf, IntPtr.Zero);
                if (rc == MAXT_ERROR_BUFFER_ALLOCATED)
                    rc = mxfRxSamplingBufferGet(channel, out sampBuf);
            }


            // Host allocation
            if (rc == MAXT_SUCCESS)
            {
                try
                {
                    rxBuffer = Marshal.AllocHGlobal((int)rxBufferSize);
                }
                catch (OutOfMemoryException)
                {
                    rc = MAXT_ERROR_MEM;
                }
            }


            // Read and display recv records (1000 times)
            while ((rc == MAXT_SUCCESS) && (c < 1000))
            {


                rc = mxfASCBRxSamplingRead(sampBuf, MXF_RXSAMPLING_FLAG_DEFAULT, 0, rxBufferSize, out msgCount, out byteCount, rxBuffer);
                if ((rc == MAXT_SUCCESS) && (msgCount != 0))
                {
                    p = rxBuffer;
                    for (i = 0; i < (Int32)msgCount; i++)
                    {
                        rec = (MXF_ASCB_SAMPREC)Marshal.PtrToStructure(p, typeof(MXF_ASCB_SAMPREC));


                        /* Extract Data, Log and Display Here */


                        rc = mxfASCBNextSamplingRecordPtrGet(p, out p);
                    }

                }
            }
0 Kudos
Message 1 of 8
(2,761 Views)

The vendor has the API documentation and the installation files available on their website, so clearly not protected by NDA. I am therefore attaching the DLL and the .net node to this post for anyone who wants to try to crack this nut.

0 Kudos
Message 2 of 8
(2,758 Views)
Solution
Accepted by topic author ChrisLudwig

Disclaimer: I have very little experience with C#

 

The documentation says the methode expects a void* https://www.maxt.com/mxf/group__group___rx_sampling.html#gad8126b455c79d5faf31f575f63a2e78a

I imagine you can create the target object and pass a pointer to it to the library.

Stackoverflow says it works like this https://stackoverflow.com/questions/17339928/c-sharp-how-to-convert-object-to-intptr-and-back

 

So in LabVIEW

 

mscorlibmscorlib

Maybe you can work with that.

Message 3 of 8
(2,694 Views)

That looks great! 

 

I'm having an issue making the System.Runtime.InteropServices constructor. When I select that assembly in the constructor, I get no public classes that can be created. Any ideas what is causing that? I'm running 32 bit LV for this project.

0 Kudos
Message 4 of 8
(2,673 Views)

@ChrisLudwig wrote:

That looks great! 

 

I'm having an issue making the System.Runtime.InteropServices constructor. When I select that assembly in the constructor, I get no public classes that can be created. Any ideas what is causing that? I'm running 32 bit LV for this project.


That's not the assembly.  "mscorlib" is the assembly, "System.Runtime.InteropServices" is the namespace within that assembly.

Message 5 of 8
(2,666 Views)

I follow now. Thanks for all the help. The code in the box is what I put together to go from the IntPtr back to LV data. Let me know if that looks wrong. Thanks again for all the help. 

 

 

Convert Ptr to LV Data.png

0 Kudos
Message 6 of 8
(2,622 Views)

I can’t comment on the actual correctness but if I haven’t miscounted something you create in total 7 refnums each time you run this code, that represent a .Net object and never close them. That will cause new memory to be allocated that is never freed! A classical memory leak!

Rolf Kalbermatter
My Blog
Message 7 of 8
(2,611 Views)

Do you need to do the Alloc? I thought the Constructor allocated memory for itself?

G# - Award winning reference based OOP for LV, for free! - Qestit VIPM GitHub

Qestit Systems
Certified-LabVIEW-Developer
0 Kudos
Message 8 of 8
(2,579 Views)