如何在启动此可执行程序的另一个实例时更新 运行 应用程序的 WinForms 控件?

How to update a WinForms control of a running application when another instance of this executable program is launched?

我制作了单实例应用程序,但我的问题是,我不知道如何获取第一个打开的 FormMain 实例并更新表单 TextBox! 你能帮帮我吗?

static void Main(string[] args)
{
    bool result;
    Mutex mutex = new System.Threading.Mutex(true, "unique_name", out result);

    if (!result)
    {
        **/* 
          CALL OPENED FORM INSTANCE AND UPDATE TEXTBOX
         */**

        return;
    }

    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(true);
    Application.Run(new FormMain(args));

    GC.KeepAlive(mutex);
}

您可以像这样使用命名管道进程间通信:

使用次数

using System;
using System.IO.Pipes;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Runtime.Serialization.Formatters.Binary;
using System.Threading;

静态变量

static public bool AllowApplicationMultipleInstances { get; private set; } = true;

static private Mutex ApplicationMutex;

static private NamedPipeServerStream IPCServer;

应用程序唯一标识符

static public string GetGUID()
{
  object[] attributes = Assembly.GetExecutingAssembly()
                                .GetCustomAttributes(typeof(GuidAttribute), false);
  return ( (GuidAttribute)attributes[0] ).ToString();
}

只检查一个实例并初始化服务器

static private bool CheckApplicationOnlyOneInstance(AsyncCallback duplicated)
{
  AllowApplicationMultipleInstances = false;
  string guid = GetGUID();
  ApplicationMutex = new Mutex(true, guid, out bool created);
  if ( created )
    CreateIPCServer(duplicated);
  else
  {
    var client = new NamedPipeClientStream(".", guid, PipeDirection.InOut);
    client.Connect();
    new BinaryFormatter().Serialize(client, "BringToFront");
    client.Close();
  }
  return created;
}

创建服务器

static private void CreateIPCServer(AsyncCallback duplicated)
{
  IPCServer = new NamedPipeServerStream(GetGUID(),
                                        PipeDirection.InOut,
                                        1,
                                        PipeTransmissionMode.Message,
                                        PipeOptions.Asynchronous);
  IPCServer.BeginWaitForConnection(duplicated, IPCServer);
}

回复请求

static private void IPCRequest(IAsyncResult ar)
{
  var server = ar.AsyncState as NamedPipeServerStream;
  server.EndWaitForConnection(ar);
  var command = new BinaryFormatter().Deserialize(server) as string;
  if ( command == "BringToFront" )
  {
    Console.WriteLine(command);
    //MainForm.Instance.SyncUI(() => MainForm.Instance.MenuShowHide_Click(null, null));
  }
  server.Close();
  CreateIPCServer(IPCRequest);
}

测试

static private void Test()
{
  if ( !SystemManager.CheckApplicationOnlyOneInstance(IPCRequest) )
    return;
  Console.ReadKey();
}

用法

您可以根据需要创建字符串命令。

例如,它允许将命令行参数从刚刚启动的进程传递到实际的 运行 进程。

您还可以改进这种简单的行为,以获得更复杂的系统,使用 类 框架而不是字符串命令。

对于您的应用程序,您应该能够使用:

static public FormMain MainForm;

static void Main(string[] args)
{
  if ( !SystemManager.CheckApplicationOnlyOneInstance(IPCRequest) )
    return;
  Application.EnableVisualStyles();
  Application.SetCompatibleTextRenderingDefault(true);
  MainForm = new FormMain(args);
  Application.Run(MainForm);
}

如果修改 WinForm 控件,则必须与主 UI 线程同步:

How do I update the GUI from another thread?

部分链接

PipeStream

Full Duplex Asynchronous Read/Write with Named Pipes (CodeProject)

Inter Process Communication (C# Vault)

WCF Comparison with Web Services and .NET Remoting (CodeProject)

Socket Programming In C# (C-SharpCorner)

Socket Programming in C# (GeeksForGeeks)

Simple Client-server Interactions using C# (CodeProject)