C# 如何从托管应用的一个实例向另一个实例发送消息?
我有一个WinForms应用程序,如果已经有一个实例在运行&用户试图启动另一个实例,我会在调用Application.Run()之前通过检查互斥来停止它。那部分很好用。我想做的是在终止新进程之前,将一条消息从应用程序的新实例(以及一段字符串形式的数据)传递到现有实例 我尝试调用PostMessage,在运行中的应用程序上确实收到了消息,但是我在lparam中传递的字符串失败了(是的,我已经检查了,以确保首先传递的字符串是正确的)。我怎样才能做到最好C# 如何从托管应用的一个实例向另一个实例发送消息?,c#,interop,ipc,postmessage,C#,Interop,Ipc,Postmessage,我有一个WinForms应用程序,如果已经有一个实例在运行&用户试图启动另一个实例,我会在调用Application.Run()之前通过检查互斥来停止它。那部分很好用。我想做的是在终止新进程之前,将一条消息从应用程序的新实例(以及一段字符串形式的数据)传递到现有实例 我尝试调用PostMessage,在运行中的应用程序上确实收到了消息,但是我在lparam中传递的字符串失败了(是的,我已经检查了,以确保首先传递的字符串是正确的)。我怎样才能做到最好 static class Program {
static class Program
{
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern bool PostMessage(int hhwnd, uint msg, IntPtr wparam, IntPtr lParam);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern uint RegisterWindowMessage(string lpString);
private const int HWND_BROADCAST = 0xffff;
static uint _wmJLPC = unchecked((uint)-1);
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
_wmJLPC = RegisterWindowMessage("JumpListProjectClicked");
if (_wmJLPC == 0)
{
throw new Exception(string.Format("Error registering window message: \"{0}\"", Marshal.GetLastWin32Error().ToString()));
}
bool onlyInstance = false;
Mutex mutex = new Mutex(true, "b73fd756-ac15-49c4-8a9a-45e1c2488599_ProjectTracker", out onlyInstance);
if (!onlyInstance) {
ProcessArguments();
return;
}
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm());
GC.KeepAlive(mutex);
}
internal static void ProcessArguments()
{
if (Environment.GetCommandLineArgs().Length > 1)
{
IntPtr param = Marshal.StringToHGlobalAuto(Environment.GetCommandLineArgs()[1]);
PostMessage(HWND_BROADCAST, _wmJLPC, IntPtr.Zero, param);
}
}
}
再次检查您的代码。您正在使用StringToHGlobalAuto创建字符串(很可能以Unicode结尾)。然后,调用PtrToStringAnsi,它不使用unicode 如果您无法使此解决方案正常工作,有几种选择。您可以通过查找IPC(进程间通信)来了解它们 我使用的一种方法是创建一个包含所需内容的知名文件,因为它既快速又简单。您使用命名事件锁定该文件的使用,并通过设置另一个命名事件告知“所有者”应用程序该文件已更改。“所有者”偶尔检查事件,或者启动工作线程来监视它
同样,IPC有很多风格,如果这些想法不起作用,请继续寻找。现在有更简单和现代的方法来进行跨进程通信。特别是,请查看WCF
尽管我承认有一个小小的学习曲线。一旦你弄明白了,这真的很容易。您甚至可以通过编程来完成这一切,这样就不必担心任何配置混乱。这里有一个简单的方法。我没有运行代码,但你明白了
class Program
{
static Thread listenThread;
static void Main(string[] args)
{
try
{
using (Mutex mutex = new Mutex(true, "my mutex"))
{
listenThread = new Thread(Listen);
listenThread.IsBackground = true;
listenThread.Start();
}
}
catch (ApplicationException)
{
using (Mutex mutex = Mutex.OpenExisting("my mutex"))
{
mutex.WaitOne();
try
{
using (NamedPipeClientStream client = new NamedPipeClientStream("some pipe"))
{
using (StreamWriter writer = new StreamWriter(client))
{
writer.WriteLine("SomeMessage");
}
}
}
finally
{
mutex.ReleaseMutex();
}
}
}
}
static void Listen()
{
using (NamedPipeServerStream server = new NamedPipeServerStream("some pipe"))
{
using (StreamReader reader = new StreamReader(server))
{
for (; ; )
{
server.WaitForConnection();
string message = reader.ReadLine();
//Dispatch the message, probably onto the thread your form
// was contructed on with Form.BeginInvoke
}
}
}
}
格雷格
StringToHGlobalAuto创建的非托管指针仅在创建它的进程空间中有效。无法从其他进程访问它引用的内存
要将数据从一个应用程序传递到另一个应用程序,请将SendMessage()与WM_COPYDATA消息一起使用
斯科特似乎缺少一个完整的例子。我费了一点劲才让一个工作示例运行起来。因此,这是我的单实例应用程序的最小实现,当运行多次时,它将消息(第一个命令行参数)传递给第一个实例。如果像我这样的人需要一个完整的工作示例,这是一个很好的开始:
using System;
using System.IO;
using System.IO.Pipes;
using System.Threading;
namespace MutexApp
{
class Program
{
private const string PIPE_NAME = "MY_PIPE"; // Name of pipe
private const string MUTEX_NAME = "MY_MUTEX"; // Mutex name
static void Main(string[] args)
{
string message = "NO MESSAGE";
if (args.Length > 0) // If we have a parameter to the .exe get it
message = args[0];
bool firstinstance = false;
Mutex mutex = new Mutex(true, MUTEX_NAME, out firstinstance);
if (firstinstance) // We are the first instance of this process
{
Console.WriteLine("First instance started");
Console.WriteLine("Message: " + message);
Console.WriteLine("Waiting for messages (ctrl+c to break)...");
while (true) { ProcessNextClient(); } // Unfinite loop that listens for messages by new clients
}
else // This process is already running, parse message to the running instance and exit
{
{
try
{
using (NamedPipeClientStream client = new NamedPipeClientStream(PIPE_NAME)) // Create connection to pipe
{
client.Connect(5000); // Maximum wait 5 seconds
using (StreamWriter writer = new StreamWriter(client))
{
writer.WriteLine(message); // Write command line parameter to the first instance
}
}
} catch (Exception ex)
{
Console.WriteLine("Error: "+ex.Message);
}
}
}
mutex.Dispose();
}
private static void ProcessNextClient()
{
try
{
NamedPipeServerStream pipeStream = new NamedPipeServerStream(PIPE_NAME, PipeDirection.InOut, NamedPipeServerStream.MaxAllowedServerInstances); // Create Server pipe and listen for clients
pipeStream.WaitForConnection(); // Wait for client connection
using (StreamReader reader = new StreamReader(pipeStream)) // Read message from pipe stream
{
string message = reader.ReadLine();
Console.WriteLine("At " + DateTime.Now.ToLongTimeString()+": " + message); // Print message on screen
}
}
catch (Exception e)
{
Console.WriteLine("Error: " + ex.Message);
}
}
}
}
using System;
using System.IO;
using System.IO.Pipes;
using System.Threading;
namespace MutexApp
{
class Program
{
private const string PIPE_NAME = "MY_PIPE"; // Name of pipe
private const string MUTEX_NAME = "MY_MUTEX"; // Mutex name
static void Main(string[] args)
{
string message = "NO MESSAGE";
if (args.Length > 0) // If we have a parameter to the .exe get it
message = args[0];
bool firstinstance = false;
Mutex mutex = new Mutex(true, MUTEX_NAME, out firstinstance);
if (firstinstance) // We are the first instance of this process
{
Console.WriteLine("First instance started");
Console.WriteLine("Message: " + message);
Console.WriteLine("Waiting for messages (ctrl+c to break)...");
while (true) { ProcessNextClient(); } // Unfinite loop that listens for messages by new clients
}
else // This process is already running, parse message to the running instance and exit
{
{
try
{
using (NamedPipeClientStream client = new NamedPipeClientStream(PIPE_NAME)) // Create connection to pipe
{
client.Connect(5000); // Maximum wait 5 seconds
using (StreamWriter writer = new StreamWriter(client))
{
writer.WriteLine(message); // Write command line parameter to the first instance
}
}
} catch (Exception ex)
{
Console.WriteLine("Error: "+ex.Message);
}
}
}
mutex.Dispose();
}
private static void ProcessNextClient()
{
try
{
NamedPipeServerStream pipeStream = new NamedPipeServerStream(PIPE_NAME, PipeDirection.InOut, NamedPipeServerStream.MaxAllowedServerInstances); // Create Server pipe and listen for clients
pipeStream.WaitForConnection(); // Wait for client connection
using (StreamReader reader = new StreamReader(pipeStream)) // Read message from pipe stream
{
string message = reader.ReadLine();
Console.WriteLine("At " + DateTime.Now.ToLongTimeString()+": " + message); // Print message on screen
}
}
catch (Exception e)
{
Console.WriteLine("Error: " + ex.Message);
}
}
}
}