Search code examples
c#marshallingdisposememorystream

Writing to memory in .NET and pick up data of process in labview


I am using the Kinect Face-Tracking Basics WPF example to collect data from an object. I can access the data in a text file etc but I want to write the data to managed memory in a C# process and have labview's .NET program pick up the data from same location.

So far, this is what I've got:

                    this.facePoints3D = frame.Get3DShape();

                   // using (MemoryStream stream = new MemoryStream())
                   // {
                        //var sw = new StreamWriter(stream);
                        int n = 121;
                        foreach (Vector3DF[] vector in facePoints3D.GetSlices(n))
                        {
                            //convert from float to byte array before we pass on to memory
                            var bytearray = new byte[vector.Length * this.facePoints3D.Count];
                            Buffer.BlockCopy(vector, 0, bytearray, 0, bytearray.Length);

                           //Initialize unmanaged memory to hold array.
                            int size = Marshal.SizeOf(bytearray[0]) * bytearray.Length;

                            IntPtr pnt = Marshal.AllocHGlobal(size);

                            try
                            {
                                //copy the array to unmanaged memory.
                                Marshal.Copy(bytearray, 0, pnt, bytearray.Length);

                                // Copy the unmanaged array back to another managed array.

                                byte[] bytearray2 = new byte[bytearray.Length];

                                Marshal.Copy(pnt, bytearray2, 0, bytearray.Length);

                                //Console.WriteLine("The array was coppied to unmanaged memory and back.");
                            }
                            finally
                            {
                                // Free the unmanaged memory.
                                Marshal.FreeHGlobal(pnt);
                            }

}

Thus far, I have the labview program configured correctly as

Process A (c#): MemoryStream Buffer -> Marshal AllocHGlobal -> Marshal Copy - > Marshal Dispose -> IntPtr ToInt64 Process B (labview): IntPtr value -> Marshall AllocHGlobal -> Marshal Copy -> Destination

Now the labview end runs well but it doesn't appear to be picking up the values from the Memory location.

Advice please?


Solution

  • Are those 2 separate processes? (2 separate exes). If so, you are not going to be able to share memory via direct allocation due to Process Isolation (1 process cannot see another process's memory).

    Assuming that your answer is "yes" (2 separate processes), consider using Named Pipes to communicate cross process (or wrap it up with WCF)

    Interprocess communication with Named Pipes: http://msdn.microsoft.com/en-us/library/bb546085(v=vs.110).aspx

    WCF Tutorial: basic interprocess communication: http://tech.pro/tutorial/855/wcf-tutorial-basic-interprocess-communication

    You could also use a memory-mapped file: http://www.abhisheksur.com/2012/02/inter-process-communication-using.html

    EDIT

    Added an example of using the binary serializer instead of doing manual memory copies of the structure. You can write the resulting byte arrays to your memory mapped file. This solution does require that you apply the [Serializable] attribute to your Vector3DF structure, and it assumes that the code reading the memory has the same type definition for Vector3DF.

    (note: in your code in the comments, it looked as though you are working with an array of arrays of Vector3DF structs, so that's how I modeled the serialization code. Adjust as necessary

    
            public byte[] SerializeVectors(Vector3DF[][] vectors)
            {
                var formatter = new BinaryFormatter();
                // note: if you are using a stream to write to the memory mapped file, 
                // you could pass it in instead of using this memory stream as an intermediary
                using (var stream = new MemoryStream())
                {
                    formatter.Serialize(stream, vectors);
                    return stream.ToArray();
                }
            }
    
            public Vector3DF[][] DeserializeVectors(byte[] vectorBuffer)
            {
                var formatter = new BinaryFormatter();
                using (var stream = new MemoryStream(vectorBuffer, false))
                {
                    return (Vector3DF[][])formatter.Deserialize(stream);
                }
            }
    

    Here is a link to a Gist that contains working code and a unit test so that you can play around with it: https://gist.github.com/jsmarsch/d0dcade8c656b94f5c1c