将参数传递给同一应用程序的另一个实例

Passing argument to another instance of the same application

我的小应用程序有严重问题;基本上很容易理解:

我的软件,打开后,一切正常。

我想专注于打开另一个实例(我的意思是再次打开.exe),检查它是否已经打开。如果不是简单地启动应用程序,但如果它已经是 运行(也就是第二个或更多实例)"simply" 将输入参数(args 字符串数组)传递给第一个实例,这将适当地处理它。

这是我的 program.cs

static class Program
{
    static Mutex mutex = new Mutex(true, "{blabla}");

    [STAThread]
    static void Main(String[] args)
    {
        if (mutex.WaitOne(TimeSpan.Zero, true))
        {
            //First Instance!

            try
            {
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);

                CALL A MY STATIC METHOD, DO SOME THINGS

                Application.Run(new Form1());
            }
            finally
            {
                mutex.ReleaseMutex();
            }
        }
        else
        {
            //Not-so-first instance!
            CALL A STATIC METHOD, 
            DO OTHER THINGS LIKE COMUNICATE WITH FIRST INSTANCE

            SIMPLY CLOSE.
        }
    }
}

如果它已经打开但(当然)它不能与主实例进行任何通信,这将仅识别(使用互斥量)。

我已经尝试了很多东西,但我无法让它工作。

我试过 this 但我真的不明白(在浪费了很多时间之后)如何放置我的 "first time" 代码和 "already running" 代码。

也试过MSMQ,但我做不到。

有人可以帮助我吗?这是一个基本的软件,可以做一些非常基本的事情,但我花了一天时间让它按照我想要的方式工作!

使用Mutex.

    // Generate your GUID and put it here
    private const string ProgramRunningGuid = "BD2023EE-F7B3-47B8-8C76-32668196E4D3";
    private Mutex _mutex;

    private bool IsProgramRunning()
    {
        bool createdNew;
        // It returns a bool value determining if a Mutex that created is new
        // If the program is already running mutex wouldn't be new
        _mutex = new Mutex(true, ProgramRunningGuid, out createdNew);
        return !createdNew;
    }

程序退出时需要释放互斥量:

    _needlesRunningMutex.ReleaseMutex();

如果您想关注已经 运行 的应用程序实例,您可以在此处使用有效解决方案查看我的答案:

如果您只需要共享一些 bool 参数来确定事物是打开还是关闭,您可以为它们中的每一个使用互斥量。

如果您需要在启动时将参数传递给您的 .exe,请检查这个问题:

如果您需要在 运行 应用程序的两个实例之间进行连续通信,请使用 MSMQ。如果有任何问题,我会尽力帮助你。

在这里查看如何使用 MSMQ:https://github.com/IvanYurchenko/MSMQSample

最简单的通信方式之一是从第二个实例向第一个实例发送 Windows 消息。第二个实例将使用 PostMessage 发送消息,第一个实例将重写 Form1 的 WndProc 方法来处理消息。

这里有一个例子: Send message to a Windows process (not its main window)

该问题还有一个答案,使用管道(和 WCF)进行通信。

进程间通信有多种形式。您使用哪一个取决于您的需要,例如 Windows 消息不能携带大量信息,而管道可以以非常高的速度传输数据。

更新 一个简单的替代方案可能是 IPCChannel 。这允许您在第一个实例中创建一个可以被第二个实例调用的对象。您可以在该对象上创建一个方法并将您的数据作为参数传递

我通过文本文件传递参数(我相信你可以从 VB.NET/pseudocode 翻译过来):

Private _uniqueEventName As String
Private _uniqueMutexName As String
Private _eventWaitHandle As EventWaitHandle
Private _mutex As Mutex

Private Sub ensureSingleInstance()
    _uniqueEventName = "{0ae64101-e630-4221-bf10-123fdddd5ab2}" + Assembly.GetEntryAssembly().GetName().Name
    _uniqueMutexName = "{03169a07-793b-48c6-8ceb-1232388cb69a}" + Assembly.GetEntryAssembly().GetName().Name

    Dim isOwned As Boolean
    _mutex = New Mutex(True, _uniqueMutexName, isOwned)
    _eventWaitHandle = New EventWaitHandle(False, EventResetMode.AutoReset, _uniqueEventName)

    GC.KeepAlive(_mutex)

    If isOwned Then
        Dim thread As Thread = New Thread(
                               Sub()
                                   While _eventWaitHandle.WaitOne()
                                       Application.Dispatcher.BeginInvoke(
                                           Sub()
                                               ' ****************************************************
                                               ' READ AND PROCESS THE ARGUMENTS FROM C:\MYAPPARGS.TXT
                                               ' ****************************************************

                                               If Not Application.MainWindow Is Nothing Then
                                                   _loggingDAL.Log("Activating main window")

                                                   If (Application.MainWindow.WindowState = WindowState.Minimized Or Application.MainWindow.Visibility = Visibility.Hidden) Then
                                                       Application.MainWindow.Show()
                                                       Application.MainWindow.WindowState = WindowState.Normal
                                                   End If

                                                   Application.MainWindow.Activate()
                                                   Dim topMost As Boolean = Application.MainWindow.Topmost
                                                   Application.MainWindow.Topmost = True
                                                   Application.MainWindow.Topmost = topMost
                                                   Application.MainWindow.Focus()
                                               End If
                                           End Sub)
                                   End While
                               End Sub)
        thread.IsBackground = True
        thread.Start()
    Else
        _loggingDAL.Log("There is already an instance running -> switching and quitting")

        ' ***************************************
        ' WRITE THE ARGUMENTS TO C:\MYAPPARGS.TXT
        ' ***************************************

        _eventWaitHandle.Set()
        Application.Shutdown()
    End If
End Sub