You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现两个控制台程序间的消息传递?(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来实现。核心步骤是:

  1. 让控制台2获取自己的窗口句柄,或者让控制台1通过窗口标题找到控制台2的句柄;
  2. 控制台1通过SendMessage()向控制台2发送自定义消息,并附带数据;
  3. 控制台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);
            }
        }
    }
}

注意:

  1. 自定义消息要保证两个程序注册的消息ID一致,所以用RegisterWindowMessage()来注册,避免冲突;
  2. 控制台2需要启动消息循环(Application.Run())才能接收消息;
  3. 如果不知道控制台2的窗口标题,可以通过进程ID来查找窗口句柄,需要额外调用OpenProcess和GetWindowThreadProcessId等API。

内容的提问来源于stack exchange,提问作者Serban Marin-Eusebiu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 20:52:43