I have two applications called SENDER and RECEIVER.
RECEIVER will be launched by SENDER with the System.Diagnostics.Process.Start
method
RECEIVER will be launched in hidden mode so it does not have a MainWindowHandle
.
Then we could use Win32.WM_COPYDATA
in order send message to RECEIVER, but it needs MainWindowHandle
so we can't.
What I need is ability to send and receive messages periodically by any method.
I checked the following link for a manual about MainWindowHandle
, but it didn't help:
Send message to a Windows process (not its main window)
One solution might be an object from System.Diagnostics.Process
which might help us to send messages to a process.
For a process running on the same machine, probably the lightest weight solution is to use PostThreadMessage(). I'm really surprised no one gave this answer, it's old school Windows programming. The OP was very close. Observe:
All of the ingredients are there, it's a matter of putting them together. Conceptually it's straightforward, the tricky part is communicating the RECEIVER's main thread ID to the SENDER. You have a few options:
Options 1 & 2 seem like security exploits, so for this example I went with option 3 and shared the thread ID in a tiny memory mapped file.
The RECEIVER looks something like this
enum WM { USER = 0x400 }
class MyMessageFilter : IMessageFilter
{
public bool PreFilterMessage(ref Message m)
{
if ((WM)m.Msg == WM.USER)
{
Console.WriteLine("WM_USER received.");
return true;
}
return false;
}
}
class RECEIVER : IDisposable
{
MemoryMappedFile mmf;
bool disposed = false;
public void MyMessageLoop()
{
uint mainThreadId = GetCurrentThreadId();
Console.WriteLine(mainThreadId);
mmf = MemoryMappedFile.CreateNew(Constants.ThreadIDFileName, IntPtr.Size, MemoryMappedFileAccess.ReadWrite);
using (var accessor = mmf.CreateViewAccessor(0, IntPtr.Size, MemoryMappedFileAccess.ReadWrite))
{
accessor.Write(0, mainThreadId);
}
Application.AddMessageFilter(new MyMessageFilter());
Application.Run();
}
[DllImport("kernel32.dll")]
static extern uint GetCurrentThreadId();
// Implement IDisposable and ~RECEIVER() to delete the semaphore, omitted for brevity
// https://learn.microsoft.com/en-us/dotnet/api/system.idisposable?view=netframework-4.7.2
#region
...
#endregion
}
And the SENDER looks something like this
enum WM { USER = 0x400 }
class Program
{
static void Main(string[] args)
{
string procName = "RECEIVER";
Process[] processes = Process.GetProcesses();
Process process = (from p in processes
where p.ProcessName.ToUpper().Contains(procName)
select p
).First();
uint threadId;
using (var mmf = MemoryMappedFile.OpenExisting(Constants.ThreadIDFileName, MemoryMappedFileRights.Read))
using (var accessor = mmf.CreateViewAccessor(0, IntPtr.Size, MemoryMappedFileAccess.Read))
{
accessor.Read(0, out serviceThreadId);
}
PostThreadMessage(threadId, (uint)WM.USER, UIntPtr.Zero, IntPtr.Zero);
}
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("user32.dll", SetLastError = true)]
public static extern bool PostThreadMessage(uint threadId, uint msg, IntPtr wParam, IntPtr lParam);
}
There are different ways to share information between 2 processes.
First at all you have to think if both processes are going to be always in the same machine or not when your application scales up.
Different Machines
Always in same machine.
Preferred choice: MSMQ
If I were you I would preserve the ability of having processes in different machines so I would use, as Maarten suggested, two windows services that uses MSMQ to communicate. Why?
Second preferred choice: Restful Web Service
If you don't want to use MSMQ I would use two Restful Web Service hosted in IIS to communicate both processes. It can be useful if you have an scenario where RECEIVER is not interested in messages from SENDER if they arrive late.
Old question, I know.
Stumbled on it, as I have a somewhat similar task.
One app started from the another - it will end again, but nobody knows when.
1. app can start 2. again, but must not until previous instances of 2. has exited.
Always on same PC (and Windows).
The simple thing is off hand to use the registry to set a value, when 2. program is running, and remove/reset it again when it exits.
1. app can check the registry to see if it is OK to start another instance of the 2. app.
You can also use the registry to pass values between the apps. Drawback is, that apps must poll the registry, instead of sending messages. Simpler but less effective.
So probably dependent on what it is needed for.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With