Reputation: 29
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
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