LOGO OA教程 ERP教程 模切知识交流 PMS教程 CRM教程 开发文档 其他文档  
 
网站管理员

C# 如何确保程序只运行一个实例并接收外部参数?

admin
2025年12月10日 1:36 本文热度 5

前言

在开发一款接收其他程序命令行参数并显示为列表的应用时,我们遇到了一个挑战:如何防止程序被多次启动,并且确保新收到的消息能正确传递给已经运行的实例。本文将详细介绍如何通过C#代码实现这一目标,包括防止重复运行、激活已有窗口以及消息传递。

效果图

正文

1、命令行读取

首先,需要从命令行中读取传入的参数。这可以通过修改Program.cs中的Main方法来完成:

[STAThread]
static void Main(string[] args)
{
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);
    Application.Run(new Form1(args));
}

在此基础上,在窗口初始化时处理这些参数,以添加到列表中。

2、禁止程序重复运行

为了保证程序不会被重复运行,我们可以使用以下代码检测是否已有相同进程正在运行:

public static Process RunningInstance()
{
    Process current = Process.GetCurrentProcess();
    Process[] processes = Process.GetProcessesByName(current.ProcessName);
    foreach (Process process in processes)
    {
        if (process.Id != current.Id && Assembly.GetExecutingAssembly().Location.Replace("/""\\") == current.MainModule.FileName)
        {
            return process;
        }
    }
    return null;
}

如果检测到已有实例,则通过以下代码激活它:

[DllImport("User32.dll")]
private static extern bool ShowWindowAsync(IntPtr hWnd, int cmdShow);
[DllImport("User32.dll")]
private static extern bool SetForegroundWindow(IntPtr hWnd);

public static void HandleRunningInstance(Process instance)
{
    ShowWindowAsync(instance.MainWindowHandle, WS_SHOWNORMAL);
    SetForegroundWindow(instance.MainWindowHandle);
}

3、消息传递机制

当有新的命令行参数时,我们需要将其发送给已有的程序实例。这里采用SendMessage API来实现:

const int WM_COPYDATA = 0x004A;

[DllImport("User32.dll", EntryPoint = "SendMessage")]
private static extern int SendMessage(IntPtr hWnd, int msg, uint wParam, ref COPYDATASTRUCT lParam);
[DllImport("User32.dll", EntryPoint = "FindWindow")]
private static extern int FindWindow(string lpClassName, string lpWindowName);

publicstruct COPYDATASTRUCT
{
    public IntPtr dwData;
    publicint cbData;
    [MarshalAs(UnmanagedType.LPStr)]
    publicstring lpData;
}

封装一个方法用于发送消息:

static void Send(string[] args)
{
    int WINDOW_HANDLER = FindWindow(null@"你的窗口标题");
    if (WINDOW_HANDLER != 0)
    {
        StringBuilder sb = new StringBuilder();
        foreach (string item in args)
        {
            sb.Append(item + " ");
        }
        byte[] sarr = System.Text.Encoding.Default.GetBytes(sb.ToString());
        int len = sarr.Length;
        COPYDATASTRUCT cds;
        cds.dwData = (IntPtr)100;
        cds.lpData = sb.ToString();
        cds.cbData = len + 1;
        int sendRet = SendMessage((IntPtr)WINDOW_HANDLER, WM_COPYDATA, 0ref cds);
        if (sendRet == 0)
        {
            MessageBox.Show("传递参数失败!");
        }
    }
    else
    {
        MessageBox.Show("没有发现旧窗口!");
    }
}

最后,修改Main方法以支持上述逻辑,并在已有实例的情况下调用Send方法传递参数。

4、接收消息

在主窗体中重写DefWndProc方法来接收并处理来自其他实例的消息:

protected override void DefWndProc(ref System.Windows.Forms.Message m)
{
    constint WM_COPYDATA = 0x004A;
    switch (m.Msg)
    {
        case WM_COPYDATA:
            COPYDATASTRUCT mystr = (COPYDATASTRUCT)m.GetLParam(typeof(COPYDATASTRUCT));
            string[] s = mystr.lpData.Split(newstring[]{" "}, StringSplitOptions.RemoveEmptyEntries);
            // 处理接收到的数据
            break;
        default:
            base.DefWndProc(ref m);
            break;
    }
}

总结

通过以上步骤,实现了C#应用程序防止重复运行并能够将新接收的命令行参数传递给已有实例的功能

过程包括了命令行参数读取、进程检测、窗口激活及消息传递等多个环节。尽管界面美观度上可能有所妥协,但功能上满足了预期需求。

关键词

C#、#防止重复运行#SendMessage、COPYDATASTRUCT、#命令行参数#WinForm、WM_COPYDATA、SetForegroundWindow、ShowWindowAsync


阅读原文:原文链接


该文章在 2025/12/10 18:27:30 编辑过
关键字查询
相关文章
正在查询...
点晴ERP是一款针对中小制造业的专业生产管理软件系统,系统成熟度和易用性得到了国内大量中小企业的青睐。
点晴PMS码头管理系统主要针对港口码头集装箱与散货日常运作、调度、堆场、车队、财务费用、相关报表等业务管理,结合码头的业务特点,围绕调度、堆场作业而开发的。集技术的先进性、管理的有效性于一体,是物流码头及其他港口类企业的高效ERP管理信息系统。
点晴WMS仓储管理系统提供了货物产品管理,销售管理,采购管理,仓储管理,仓库管理,保质期管理,货位管理,库位管理,生产管理,WMS管理系统,标签打印,条形码,二维码管理,批号管理软件。
点晴免费OA是一款软件和通用服务都免费,不限功能、不限时间、不限用户的免费OA协同办公管理系统。
Copyright 2010-2025 ClickSun All Rights Reserved