2

I am trying to send constantly a jagged array of floats to a Unity app from another C# application.

I got a C# dll that uses a MarshalByRefObject and opens an Ipc channel for a simple test server app and a simple test client app. Both apps are able to share data successfully. Here is the code for the dll:

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Ipc;

namespace U2SDLL
{
    /// <summary>
    /// shared object
    /// </summary>
    public class U2SSharedObject : MarshalByRefObject
    {
        public Int32 IntegerValue { get; set; }
        public Single[] DataArray { get; set; }

        /// <summary>
        /// iitialize array
        /// </summary>
        /// <param name="arraysize">Single array size</param>
        /// <returns>=true:succeeded =false:failed</returns>
        public Boolean Init(Int32 arraysize)
        {
            IntegerValue = 0;
            DataArray = new Single[arraysize];
            return true;
        }

        /// <summary>
        /// avoid disconnection
        /// </summary>
        public override object InitializeLifetimeService()
        {
            return null;
        }
    }

    /// <summary>
    /// server class
    /// </summary>
    public class U2SServer
    {
        public U2SSharedObject SharedObject { get; set; }

        /// <summary>
        /// constructor
        /// </summary>
        public U2SServer()
        {
            // Create server channel
            IpcServerChannel channel = new IpcServerChannel("ipcU2SDLL");

            // Registratio channel
            ChannelServices.RegisterChannel(channel, false);

            // Create object and sharing
            SharedObject = new U2SSharedObject();
            SharedObject.Init(10000);
            RemotingServices.Marshal(SharedObject, "ipcRemoteObject", typeof(U2SSharedObject));
        }


        /// <summary>
        /// get integer value
        /// </summary>
        public Int32 GetIntegerValue()
        {
            return SharedObject.IntegerValue;
        }

        /// <summary>
        /// set integer value
        /// </summary>
        public void SetIntegerValue(Int32 value)
        {
            SharedObject.IntegerValue = value;
        }

        /// <summary>
        /// get float value array
        /// </summary>
        public Single[] GetFloatArray()
        {
            return SharedObject.DataArray;
        }

        /// <summary>
        /// set float value array
        /// </summary>
        public void SetFloatArray(Single[] data)
        {
            //Create clone data
            SharedObject.DataArray = (Single[])data.Clone();
        }
    }

    /// <summary>
    /// client class
    /// </summary>
    public class U2SClient
    {
        public U2SSharedObject SharedObject { get; set; }

        /// <summary>
        /// Constructor
        /// </summary>
        public U2SClient()
        {
            // Create client channel
            IpcClientChannel channel = new IpcClientChannel();

            // Registratio channel
            ChannelServices.RegisterChannel(channel, false);

            // Get remote object
            SharedObject = Activator.GetObject(typeof(U2SSharedObject), "ipc://ipcU2SDLL/ipcRemoteObject") as U2SSharedObject;
        }


        /// <summary>
        /// get integer value
        /// </summary>
        public Int32 GetIntegerValue()
        {
            return SharedObject.IntegerValue;
        }

        /// <summary>
        /// set integer value
        /// </summary>
        public void SetIntegerValue(Int32 value)
        {
            SharedObject.IntegerValue = value;
        }

        /// <summary>
        /// get float value array
        /// </summary>
        public Single[] GetFloatArray()
        {
            return SharedObject.DataArray;
        }

        /// <summary>
        /// set float value array
        /// </summary>
        public void SetFloatArray(Single[] data)
        {
            //Create clone data
            SharedObject.DataArray = (Single[])data.Clone();
        }

        public string TestDLL()
        {
            return "OK";
        }
    }
}

However, when trying to substitute the client app with a Unity app, I get an error whenever I try to access the SharedObject. This is what the Unity console says:

SerializationException: Invalid binary format
System.Runtime.Serialization.Formatters.Binary.ObjectReader.ReadRefTypeObjectInstance (System.IO.BinaryReader reader, System.Int64& objectId, System.Object& value, System.Runtime.Serialization.SerializationInfo& info) (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.Runtime.Serialization.Formatters.Binary/ObjectReader.cs:281)
System.Runtime.Serialization.Formatters.Binary.ObjectReader.ReadObject (BinaryElement element, System.IO.BinaryReader reader, System.Int64& objectId, System.Object& value, System.Runtime.Serialization.SerializationInfo& info) (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.Runtime.Serialization.Formatters.Binary/ObjectReader.cs:179)
System.Runtime.Serialization.Formatters.Binary.ObjectReader.ReadNextObject (BinaryElement element, System.IO.BinaryReader reader) (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.Runtime.Serialization.Formatters.Binary/ObjectReader.cs:130)
System.Runtime.Serialization.Formatters.Binary.ObjectReader.ReadObjectGraph (BinaryElement elem, System.IO.BinaryReader reader, Boolean readHeaders, System.Object& result, System.Runtime.Remoting.Messaging.Header[]& headers) (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.Runtime.Serialization.Formatters.Binary/ObjectReader.cs:104)
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.NoCheckDeserialize (System.IO.Stream serializationStream, System.Runtime.Remoting.Messaging.HeaderHandler handler) (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.Runtime.Serialization.Formatters.Binary/BinaryFormatter.cs:179)
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize (System.IO.Stream serializationStream) (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.Runtime.Serialization.Formatters.Binary/BinaryFormatter.cs:136)
System.Runtime.Remoting.Channels.Ipc.Win32.IpcTransport.Read (ITransportHeaders& headers, System.IO.Stream& responseStream)
System.Runtime.Remoting.Channels.Ipc.Win32.IpcClientChannelSink.ProcessMessage (IMessage msg, ITransportHeaders requestHeaders, System.IO.Stream requestStream, ITransportHeaders& responseHeaders, System.IO.Stream& responseStream)
System.Runtime.Remoting.Channels.BinaryClientFormatterSink.SyncProcessMessage (IMessage msg)

NamedPipeException: The pipe is being closed.

System.Runtime.Remoting.Channels.Ipc.Win32.NamedPipeSocket.Send (System.Byte[] buffer, Int32 offset, Int32 count)
System.Runtime.Remoting.Channels.Ipc.Win32.NamedPipeStream.Write (System.Byte[] buffer, Int32 offset, Int32 count)
System.Runtime.Remoting.Channels.Ipc.Win32.IpcTransport.Write (ITransportHeaders header, System.IO.Stream requestStream)
System.Runtime.Remoting.Channels.Ipc.Win32.IpcClientChannelSink.ProcessMessage (IMessage msg, ITransportHeaders requestHeaders, System.IO.Stream requestStream, ITransportHeaders& responseHeaders, System.IO.Stream& responseStream)
System.Runtime.Remoting.Channels.BinaryClientFormatterSink.SyncProcessMessage (IMessage msg)

I get the "OK" string whenever I call the "TestDLL" function within the dll so I assume that the dll is correctly integrated as a plugin. I also tried building as x86 and x64 and downgrading the .net framework but the issue remains.

Could you please point me in the right direction to solve this issue? Or, if you know of a better way to send data from a non Unity App to a Unity App, please let me know!

Thank you!

Adrian H
  • 61
  • 6
  • Have you tried used the target framework `Unity 3.5 .net Subset ...` in project properties ? – aybe Jan 26 '17 at 18:49
  • I was using `Unity 3.5 .net full Base Class Libraries`. Just changed it to `Unity 3.5 .net Subset Base Class Libraries`. It seems `System.Runtime.Remoting.Channels.Ipc` doesn't exist in the subset because is throwing me a "does not exist in the namespace" error. I get the same error on Unity when adding that namespace, even after setting the API Compatibility Level to .NET 2.0. Could this be the cause? How could I add this library as a plugin? When I add the dll from .net I get a mono exception `Invalid IL code in System.Runtime.Remoting.Channels.Ipc.IpcClientChannel:get_ChannelName()` – Adrian H Jan 27 '17 at 23:34
  • 1
    I thought you were using the regular framework ... Stick to unity full base version. I think your problem might be because of subtle differences between (bugs) net and Mono assemblies (I guess). Have you thought about a text format like Xml ? Serialization using DataContractSerializer (which maintains references). Or maybe the simplest/ fastest way for you to try: with Newtonsoft Json (see Unity fork in github) (it supports references serialization too) – aybe Jan 28 '17 at 07:08
  • 1
    By the way another example of communication between two processes is Unity and the Visual Studio plugin : They talk through HTTP – aybe Jan 28 '17 at 07:11

0 Answers0