nb-1999
nb-1999

Reputation: 29

Memory Mapped Files between two processes

I created a C# program which does some stuff. Let's call it Program B. I want to open Program B's executable in another program, Program A, I am creating also in C#. What I want to do is to get some information(actually a custom object) from Program B on a button click which also will close the program and add the information in a List in Program A. I want to use Memory Mapped Files for this, but somehow I didn't manage to do this until now. I have created a class:

public class MemoryMappedFileCommunicator{
 public MemoryMappedFileCommunicator()
        {
            MemoryMappedFile = MemoryMappedFile.CreateOrOpen(MMF_FILE_NAME, MMF_MAX_SIZE);
           
            
            // Create a stream which allows it to write data from offset 0 to 1024 (whole memory)
            MemoryMappedViewStream = MemoryMappedFile.CreateViewStream(0, MMF_VIEW_SIZE);
            
            _commandToSend = new Command();
            //callback = new SendOrPostCallback(OnDataReceivedInternal);
            //operation = AsyncOperationManager.CreateOperation(null);
        }
}

I tried using SendOrPostCallback seen in a tutorial, but it didn't make sense to me. I also tried using an event handler, but my event did not fire. What I actually want to do is to fire an event every time I finished writing in the file, so Program A could read the information and put it into a List.

Write function looks like this:

public void WriteData(MyCustomObject obj)
        {
            FileStream writer = new FileStream(MMF_FILE_NAME, FileMode.Append);
            DataContractSerializer ser = new(typeof(MyCustomObject ));
            ser.WriteObject(writer, obj);
            writer.Close();
            DataWrittenEvent();

        }

My delegate is void and has no parameters

Read function looks like this:

public MyCustomObject ReadData()
        {
            FileStream reader = new FileStream(MMF_FILE_NAME, FileMode.Open);
            XmlDictionaryReader xmlDictionaryReader = XmlDictionaryReader.CreateTextReader(reader, new XmlDictionaryReaderQuotas());
            DataContractSerializer ser = new DataContractSerializer(typeof(MyCustomObject ));

            MyCustomObject deserializedObj = (MyCustomObject )ser.ReadObject(xmlDictionaryReader, true);
            xmlDictionaryReader.Close();
            reader.Close();

            return deserializedObj;
        }

In every program I create an instance of MemoryMappedFileCommunicator, but only in Program A's constructor I attach the DataWrittenEvent event, but it is null all the time.

What am I doing wrong? How could I manage to do this?

I expected to make a callback from Program B to Program A like this: Program B: get information -> serialize information -> write serialized information to MMF (this should rise an event to Program A) Program A: read from MMF -> deserialize information -> add to list

Upvotes: 1

Views: 595

Answers (1)

nb-1999
nb-1999

Reputation: 29

So I figured it out finally. The way I work with the 2 processes is the following:

I have process A from which I will open process B. Process B will calculate some stuff and on the button click "Add" it will add the information into a MemoryMappedFile (created in Process A before opening Process B). It is important to give it a name and set the HandleInheritability to HandleInheritability.Inheritable. Also an EventWaitHandle is created in Process A in order to wait for Process B to do its job. I am sending objects between the two processes, so I serialize the object and after that I write the information in the MMF. The same at reading, I deserialize the object after reading it from the MMF.

The solution looks like this:

Process A:

EventWaitHandle ewh = new EventWaitHandle(false, EventResetMode.AutoReset, "ObjectAddedEvent");
MyObject obj= new();

            using (MemoryMappedFile mmf = MemoryMappedFile.CreateOrOpen("ObjectMMF", 1024, MemoryMappedFileAccess.ReadWrite, MemoryMappedFileOptions.None, HandleInheritability.Inheritable))
            {

                Process myProcess = Process.Start(psi);
                ewh.WaitOne(); // Here we wait for Process B to do its job
                
                // This will be executed AFTER Process B finishes its task (after ewh.Set())
                using (MemoryMappedViewStream stream = mmf.CreateViewStream()) 
                {
                    BinaryReader reader = new BinaryReader(stream);
                    string receivedObjectString = reader.ReadString();
                    if (!string.IsNullOrEmpty(receivedObjectString ))
                        obj= JsonSerializer.Deserialize<MyObject>(receivedObjectString);
                }

                // AddReceivedObjectToList(obj); -- this is a function I need in my program. It adds the object received from Process B into a list in Process A, after it is read by Process A from the MMF

                ewh.Dispose();
                myProcess.Kill(); // I will kill Process B manually after Process A read everything from the MMF

Process B:

MyObject obj= GetObject();
string serializedObject = JsonSerializer.Serialize(obj);
using (MemoryMappedFile mmf = MemoryMappedFile.OpenExisting("ObjectMMF", MemoryMappedFileRights.ReadWrite, HandleInheritability.Inheritable))
                {

                    bool ewhExists = EventWaitHandle.TryOpenExisting("ObjectAddedEvent", out EventWaitHandle ewh);

                    using (MemoryMappedViewStream stream = mmf.CreateViewStream())
                    {
                        BinaryWriter writer = new BinaryWriter(stream);
                        writer.Write(serializedObject);
                    }

                    ewh.Set(); // This gives Process A a signal that it finished its job and Process A will continue to read the data from the MMF
                }

Upvotes: 0

Related Questions