我有两个名为SENDER和RECEIVER的应用程序。
RECEIVER将由SENDER以System.Diagnostics.Process
对象
RECEIVER将以隐藏模式启动,因此它没有MainWindowHandle
。
然后我们无法使用Win32.WM_COPYDATA
向RECEIVER发送邮件,因为它需要MainWindowHandle
。
我需要的是能够通过任何方法定期发送和接收消息。
我检查了手动MainWindowHandle
的以下链接,但没有帮助:
Send message to a Windows process (not its main window)
一个解决方案可能是System.Diagnostics.Process
的有用对象,它可以帮助我们将消息发送到进程。
答案 0 :(得分:14)
有两种方法可以在两个流程之间共享信息。
首先,当你的应用程序扩展时,你必须考虑两个进程是否总是在同一台机器上。
不同的机器
始终在同一台机器上。
首选:MSMQ
如果我是你,我会保留在不同机器中使用进程的能力,因此我会像Maarten建议的那样使用两个使用MSMQ进行通信的Windows服务。为什么呢?
第二选择:Restful Web Service
如果您不想使用MSMQ,我将使用IIS中托管的两个Restful Web Service来传达这两个进程。如果你有一个场景,如果他们迟到,RECEIVER对来自SENDER的消息不感兴趣,那么它会非常有用。
答案 1 :(得分:1)
CreateFromFile方法从磁盘上的现有文件创建内存映射文件。下面的示例为一个很大的文件的一部分创建一个内存映射视图,并对其一部分进行操作。
using System;
using System.IO;
using System.IO.MemoryMappedFiles;
using System.Runtime.InteropServices;
class Program
{
static void Main(string[] args)
{
long offset = 0x10000000; // 256 megabytes
long length = 0x20000000; // 512 megabytes
// Create the memory-mapped file.
using (var mmf = MemoryMappedFile.CreateFromFile(@"c:\ExtremelyLargeImage.data", FileMode.Open,"ImgA"))
{
// Create a random access view, from the 256th megabyte (the offset)
// to the 768th megabyte (the offset plus length).
using (var accessor = mmf.CreateViewAccessor(offset, length))
{
int colorSize = Marshal.SizeOf(typeof(MyColor));
MyColor color;
// Make changes to the view.
for (long i = 0; i < length; i += colorSize)
{
accessor.Read(i, out color);
color.Brighten(10);
accessor.Write(i, ref color);
}
}
}
}
}
public struct MyColor
{
public short Red;
public short Green;
public short Blue;
public short Alpha;
// Make the view brighter.
public void Brighten(short value)
{
Red = (short)Math.Min(short.MaxValue, (int)Red + value);
Green = (short)Math.Min(short.MaxValue, (int)Green + value);
Blue = (short)Math.Min(short.MaxValue, (int)Blue + value);
Alpha = (short)Math.Min(short.MaxValue, (int)Alpha + value);
}
}
下面的示例为另一个进程打开相同的内存映射文件。
using System;
using System.IO.MemoryMappedFiles;
using System.Runtime.InteropServices;
class Program
{
static void Main(string[] args)
{
// Assumes another process has created the memory-mapped file.
using (var mmf = MemoryMappedFile.OpenExisting("ImgA"))
{
using (var accessor = mmf.CreateViewAccessor(4000000, 2000000))
{
int colorSize = Marshal.SizeOf(typeof(MyColor));
MyColor color;
// Make changes to the view.
for (long i = 0; i < 1500000; i += colorSize)
{
accessor.Read(i, out color);
color.Brighten(20);
accessor.Write(i, ref color);
}
}
}
}
}
public struct MyColor
{
public short Red;
public short Green;
public short Blue;
public short Alpha;
// Make the view brigher.
public void Brighten(short value)
{
Red = (short)Math.Min(short.MaxValue, (int)Red + value);
Green = (short)Math.Min(short.MaxValue, (int)Green + value);
Blue = (short)Math.Min(short.MaxValue, (int)Blue + value);
Alpha = (short)Math.Min(short.MaxValue, (int)Alpha + value);
}
}
答案 2 :(得分:1)
对于在同一台计算机上运行的进程,最轻量的解决方案可能是使用PostThreadMessage()。我真的很惊讶没有人给出这个答案,这是老式的Windows编程。 OP非常接近。观察:
所有成分都在那里,只需将它们放在一起即可。从概念上讲很简单,棘手的部分是将RECEIVER的主线程ID传递给SENDER。您有几种选择:
选项1和2似乎是安全漏洞,因此在此示例中,我选择了选项3,并在一个很小的内存映射文件中共享了线程ID。
RECEIVER看起来像这样
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://docs.microsoft.com/en-us/dotnet/api/system.idisposable?view=netframework-4.7.2
#region
...
#endregion
}
SENDER看起来像这样
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);
}
答案 3 :(得分:0)
我认为MSMQ是个不错的选择。
答案 4 :(得分:0)
我知道老问题了。
偶然发现了它,因为我有类似的任务。
一个应用程序是从另一个应用程序开始的-它会再次结束,但没人知道何时。
1.应用可以再次启动2.,但必须等到2.的先前实例退出后才能启动。
始终在同一台PC(和Windows)上。
在程序运行时,使用注册表设置一个简单的值很容易。在退出时,请再次将其删除/重置。
1.应用程序可以检查注册表,以查看是否可以启动2.应用程序的另一个实例。
您还可以使用注册表在应用程序之间传递值。 缺点是,应用程序必须轮询注册表,而不是发送消息。简单但效果较差。
因此可能取决于所需的条件。