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

如何向C#已运行实例传递启动参数并激活窗口

实现C#单实例程序传递启动参数并激活已有窗口

要实现这个需求,核心分两步:检测已有实例和安全传递参数,下面是具体实现方案:

1. 用互斥体(Mutex)检测程序实例

在Main方法中创建全局互斥体,判断是否已有程序在运行:

  • 如果是第一个实例,正常启动窗口;
  • 如果不是第一个实例,把启动参数传递给已有实例,激活其窗口后关闭自身。

2. 用WM_COPYDATA传递参数

Windows的WM_COPYDATA消息是专门用于进程间传递数据的安全机制,适合传递字符串类的参数。

完整代码实现

Program.cs

using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Web;

namespace foo
{
    public static class Program
    {
        // 定义WM_COPYDATA消息常量
        private const int WM_COPYDATA = 0x004A;

        // 定义COPYDATASTRUCT结构体,用于传递数据
        [StructLayout(LayoutKind.Sequential)]
        private struct COPYDATASTRUCT
        {
            public IntPtr dwData;
            public int cbData;
            [MarshalAs(UnmanagedType.LPStr)]
            public string lpData;
        }

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        private static extern bool SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, ref COPYDATASTRUCT lParam);

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

        [DllImport("user32.dll")]
        private static extern bool SetForegroundWindow(IntPtr hWnd);

        [STAThread]
        public static void Main(string[] args)
        {
            // 创建全局互斥体,确保单实例
            using (var mutex = new System.Threading.Mutex(true, "UniqueFooAppMutex", out bool isNewInstance))
            {
                if (isNewInstance)
                {
                    Application.EnableVisualStyles();
                    Application.SetCompatibleTextRenderingDefault(false);
                    var mainForm = new MainForm();
                    // 把启动参数传递给主窗口
                    if (args.Length > 0)
                    {
                        args[0] = args[0].Substring(4);
                        mainForm.ReceivedArgs = HttpUtility.UrlDecode(args[0]);
                    }
                    Application.Run(mainForm);
                }
                else
                {
                    // 找到已有实例的主窗口
                    IntPtr hWnd = FindWindow(null, "MainForm"); // 这里要和Form的Text属性一致
                    if (hWnd != IntPtr.Zero)
                    {
                        // 准备要传递的参数
                        string argsStr = args.Length > 0 ? HttpUtility.UrlDecode(args[0].Substring(4)) : "";
                        var cds = new COPYDATASTRUCT
                        {
                            dwData = IntPtr.Zero,
                            cbData = argsStr.Length + 1,
                            lpData = argsStr
                        };
                        // 发送参数给已有实例
                        SendMessage(hWnd, WM_COPYDATA, IntPtr.Zero, ref cds);
                        // 激活已有窗口到顶层
                        SetForegroundWindow(hWnd);
                    }
                    // 关闭当前新实例
                    Environment.Exit(0);
                }
            }
        }
    }
}

MainForm.cs

using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace foo
{
    public partial class MainForm : Form
    {
        private const int WM_COPYDATA = 0x004A;

        [StructLayout(LayoutKind.Sequential)]
        private struct COPYDATASTRUCT
        {
            public IntPtr dwData;
            public int cbData;
            [MarshalAs(UnmanagedType.LPStr)]
            public string lpData;
        }

        public string ReceivedArgs { get; set; }

        public MainForm()
        {
            InitializeComponent();
            Text = "MainForm"; // 要和Program中FindWindow的窗口名一致
            // 初始化显示参数
            UpdateArgsDisplay();
        }

        private void UpdateArgsDisplay()
        {
            if (string.IsNullOrEmpty(ReceivedArgs))
            {
                argsTextBox.Text = "no args";
            }
            else
            {
                argsTextBox.Text = ReceivedArgs;
            }
        }

        // 重写WndProc处理WM_COPYDATA消息
        protected override void WndProc(ref Message m)
        {
            if (m.Msg == WM_COPYDATA)
            {
                var cds = (COPYDATASTRUCT)Marshal.PtrToStructure(m.LParam, typeof(COPYDATASTRUCT));
                ReceivedArgs = cds.lpData;
                UpdateArgsDisplay();
                // 激活窗口
                Activate();
            }
            base.WndProc(ref m);
        }
    }
}

关键说明

  • 互斥体命名:UniqueFooAppMutex是全局互斥体的名称,确保唯一,避免和其他程序冲突;
  • WM_COPYDATA:这是系统提供的安全进程间通信方式,无需自己处理内存释放,系统会自动管理;
  • 窗口查找:FindWindow通过窗口标题查找,确保主窗口的Text属性和查找时的参数一致;
  • 参数处理:保留了你原本的参数截取和URL解码逻辑,确保参数处理逻辑不变。

内容的提问来源于stack exchange,提问作者rver

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 11:15:38