如何实现两个控制台程序间的消息传递?(SendMessage/剪贴板方式)
当然可以实现!针对你说的两个控制台应用间的消息传递需求,我给你整理了两种可行的方案:剪贴板同步和SendMessage() 进程间通信,每种都附上手把手的代码示例,你可以直接参考。
方案一:使用剪贴板实现值同步
这种方法比较简单,核心思路是:控制台1在值发生变化时,把新值写入系统剪贴板;控制台2则定时监控剪贴板内容,一旦检测到变化就读取新值。
控制台1(值发送端)代码示例
using System; using System.Windows.Forms; namespace ConsoleSender { class Program { [STAThread] // 剪贴板操作必须在STA线程下执行 static void Main(string[] args) { int counter = 0; while (true) { // 模拟值变化 string updatedValue = $"当前计数: {counter++}"; Console.WriteLine($"发送新值: {updatedValue}"); // 将值写入剪贴板 Clipboard.SetText(updatedValue); // 每隔3秒更新一次 System.Threading.Thread.Sleep(3000); } } } }
控制台2(值接收端)代码示例
using System; using System.Windows.Forms; namespace ConsoleReceiver { class Program { [STAThread] static void Main(string[] args) { string lastValue = string.Empty; Console.WriteLine("开始监控剪贴板变化..."); while (true) { if (Clipboard.ContainsText()) { string currentValue = Clipboard.GetText(); if (currentValue != lastValue) { Console.WriteLine($"收到新值: {currentValue}"); lastValue = currentValue; } } // 每隔500毫秒检查一次剪贴板 System.Threading.Thread.Sleep(500); } } } }
注意:控制台项目需要引用
System.Windows.Forms程序集,否则无法使用Clipboard类。另外,剪贴板是全局资源,可能会被其他程序覆盖,适合对数据实时性要求不高、数据量小的场景。
方案二:使用SendMessage()实现定向消息传递
这种方法更可靠,属于Windows原生的进程间通信方式,需要借助Windows API来实现。核心步骤是:
- 让控制台2获取自己的窗口句柄,或者让控制台1通过窗口标题找到控制台2的句柄;
- 控制台1通过
SendMessage()向控制台2发送自定义消息,并附带数据; - 控制台2监听并处理收到的自定义消息。
控制台2(消息接收端)代码示例
using System; using System.Runtime.InteropServices; using System.Windows.Forms; namespace ConsoleReceiver { class Program { // 注册自定义消息ID private static readonly int WM_CUSTOM_MESSAGE = RegisterWindowMessage("WM_CUSTOM_CONSOLE_MESSAGE"); [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] private static extern int RegisterWindowMessage(string lpString); [DllImport("user32.dll")] private static extern IntPtr GetConsoleWindow(); [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] private static extern IntPtr SetWindowLongPtr(IntPtr hWnd, int nIndex, WndProcDelegate dwNewLong); [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] private static extern IntPtr CallWindowProc(IntPtr lpPrevWndFunc, IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam); private delegate IntPtr WndProcDelegate(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam); private static WndProcDelegate _wndProcDelegate; private static IntPtr _oldWndProc; static void Main(string[] args) { IntPtr consoleHandle = GetConsoleWindow(); Console.WriteLine($"当前控制台窗口句柄: {consoleHandle}"); // 替换窗口过程,监听自定义消息 _wndProcDelegate = new WndProcDelegate(WndProc); _oldWndProc = SetWindowLongPtr(consoleHandle, -4, _wndProcDelegate); Console.WriteLine("等待接收消息..."); Application.Run(); // 启动消息循环 } private static IntPtr WndProc(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam) { if (msg == WM_CUSTOM_MESSAGE) { // 解析传递的数据(这里假设传递的是字符串指针) string receivedValue = Marshal.PtrToStringUni(lParam); Console.WriteLine($"收到消息: {receivedValue}"); } // 调用原窗口过程 return CallWindowProc(_oldWndProc, hWnd, msg, wParam, lParam); } } }
控制台1(消息发送端)代码示例
using System; using System.Runtime.InteropServices; using System.Text; namespace ConsoleSender { class Program { private static readonly int WM_CUSTOM_MESSAGE = RegisterWindowMessage("WM_CUSTOM_CONSOLE_MESSAGE"); [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] private static extern int RegisterWindowMessage(string lpString); [DllImport("user32.dll", CharSet = CharSet.Auto)] private static extern IntPtr FindWindow(string lpClassName, string lpWindowName); [DllImport("user32.dll", CharSet = CharSet.Auto)] private static extern bool SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam); static void Main(string[] args) { // 替换为控制台2的窗口标题(可以在控制台2启动时看到自己的标题,或者用FindWindowByProcessId) string receiverWindowTitle = "ConsoleReceiver"; IntPtr receiverHandle = FindWindow(null, receiverWindowTitle); if (receiverHandle == IntPtr.Zero) { Console.WriteLine("未找到接收端控制台窗口"); return; } int counter = 0; while (true) { string message = $"当前计数: {counter++}"; Console.WriteLine($"发送消息: {message}"); // 将字符串转为非托管指针 IntPtr messagePtr = Marshal.StringToHGlobalUni(message); SendMessage(receiverHandle, WM_CUSTOM_MESSAGE, IntPtr.Zero, messagePtr); Marshal.FreeHGlobal(messagePtr); // 释放内存 System.Threading.Thread.Sleep(3000); } } } }
注意:
- 自定义消息要保证两个程序注册的消息ID一致,所以用
RegisterWindowMessage()来注册,避免冲突;- 控制台2需要启动消息循环(
Application.Run())才能接收消息;- 如果不知道控制台2的窗口标题,可以通过进程ID来查找窗口句柄,需要额外调用
OpenProcess和GetWindowThreadProcessId等API。
内容的提问来源于stack exchange,提问作者Serban Marin-Eusebiu
相关产品推荐
相关产品推荐

