742 Stimmen

Was ist der richtige Weg, um eine einzelne Instanz WPF-Anwendung zu erstellen?

Verwendung von C# und WPF unter .NET (anstelle von Windows-Formulare oder Konsole), was ist der richtige Weg, um eine Anwendung zu erstellen, die nur als eine einzige Instanz ausgeführt werden kann?

Ich weiß, dass es etwas mit einem mythischen Ding namens Mutex zu tun hat, aber selten finde ich jemanden, der sich die Mühe macht, anzuhalten und zu erklären, was so etwas ist.

Der Code muss auch die bereits laufende Instanz darüber informieren, dass der Benutzer versucht hat, eine zweite Instanz zu starten, und vielleicht auch alle Befehlszeilenargumente übergeben, falls welche vorhanden sind.

17 Stimmen

Gibt die CLR nicht automatisch alle nicht freigegebenen Mutexe frei, wenn die Anwendung ohnehin beendet wird?

2 Stimmen

@Cocowalla: Der Finalisierer sollte die nicht verwalteten Mutexe entsorgen, es sei denn, er kann nicht wissen, ob die Mutex von der verwalteten Anwendung erstellt oder an eine bestehende angehängt wurde.

1 Stimmen

Es ist sinnvoll, nur eine Instanz Ihrer Anwendung zu haben. Aber die Übergabe von Argumenten an eine bereits existierende Anwendung erscheint mir ein wenig albern. Ich kann keinen Grund dafür sehen, dies zu tun. Wenn Sie eine Anwendung mit einer Dateierweiterung verknüpfen, sollten Sie so viele Anwendungen öffnen, wie Benutzer Dokumente öffnen wollen. Das ist das Standardverhalten, das jeder Benutzer erwarten würde.

0voto

kakopappa Punkte 4925

Hier sind meine 2 Cents

 static class Program
    {
        [STAThread]
        static void Main()
        {
            bool createdNew;
            using (new Mutex(true, "MyApp", out createdNew))
            {
                if (createdNew) {
                    Application.EnableVisualStyles();
                    Application.SetCompatibleTextRenderingDefault(false);
                    var mainClass = new SynGesturesLogic();
                    Application.ApplicationExit += mainClass.tray_exit;
                    Application.Run();
                }
                else
                {
                    var current = Process.GetCurrentProcess();
                    foreach (var process in Process.GetProcessesByName(current.ProcessName).Where(process => process.Id != current.Id))
                    {
                        NativeMethods.SetForegroundWindow(process.MainWindowHandle);
                        break;
                    }
                }
            }
        }
    }

0 Stimmen

Was ist die Klasse "NativeMethods"?

0voto

Divins Mathew Punkte 2490

Einfach mit einer StreamWriter wie wäre es damit?

System.IO.File.StreamWriter OpenFlag = null;   //globally

und

try
{
    OpenFlag = new StreamWriter(Path.GetTempPath() + "OpenedIfRunning");
}
catch (System.IO.IOException) //file in use
{
    Environment.Exit(0);
}

0voto

Code Scratcher Punkte 1

Hier ist eine Lösung:

Protected Overrides Sub OnStartup(e As StartupEventArgs)
    Const appName As String = "TestApp"
    Dim createdNew As Boolean
    _mutex = New Mutex(True, appName, createdNew)
    If Not createdNew Then
        'app is already running! Exiting the application
        MessageBox.Show("Application is already running.")
        Application.Current.Shutdown()
    End If
    MyBase.OnStartup(e)
End Sub

0 Stimmen

Ich mag einfache Lösungen, also habe ich das zuerst ausprobiert... konnte es nicht zum Laufen bringen.

0voto

Antoine Diekmann Punkte 196

Sie können auch die CodeFluent Laufzeit das ist ein kostenloser Satz von Werkzeugen. Es bietet eine SingleInstance Klasse, um eine einzelne Instanzanwendung zu implementieren.

0voto

Tommaso Belluzzo Punkte 22266

Normalerweise verwende ich den folgenden Code für Einzelinstanzen Windows-Formulare Anwendungen:

[STAThread]
public static void Main()
{
    String assemblyName = Assembly.GetExecutingAssembly().GetName().Name;

    using (Mutex mutex = new Mutex(false, assemblyName))
    {
        if (!mutex.WaitOne(0, false))
        {
            Boolean shownProcess = false;
            Process currentProcess = Process.GetCurrentProcess();

            foreach (Process process in Process.GetProcessesByName(currentProcess.ProcessName))
            {
                if (!process.Id.Equals(currentProcess.Id) && process.MainModule.FileName.Equals(currentProcess.MainModule.FileName) && !process.MainWindowHandle.Equals(IntPtr.Zero))
                {
                    IntPtr windowHandle = process.MainWindowHandle;

                    if (NativeMethods.IsIconic(windowHandle))
                        NativeMethods.ShowWindow(windowHandle, ShowWindowCommand.Restore);

                    NativeMethods.SetForegroundWindow(windowHandle);

                    shownProcess = true;
                }
            }

            if (!shownProcess)
                MessageBox.Show(String.Format(CultureInfo.CurrentCulture, "An instance of {0} is already running!", assemblyName), assemblyName, MessageBoxButtons.OK, MessageBoxIcon.Asterisk, MessageBoxDefaultButton.Button1, (MessageBoxOptions)0);
        }
        else
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form());
        }
    }
}

Wo die einheimischen Komponenten sind:

[DllImport("User32.dll", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern Boolean IsIconic([In] IntPtr windowHandle);

[DllImport("User32.dll", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern Boolean SetForegroundWindow([In] IntPtr windowHandle);

[DllImport("User32.dll", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern Boolean ShowWindow([In] IntPtr windowHandle, [In] ShowWindowCommand command);

public enum ShowWindowCommand : int
{
    Hide                   = 0x0,
    ShowNormal             = 0x1,
    ShowMinimized          = 0x2,
    ShowMaximized          = 0x3,
    ShowNormalNotActive    = 0x4,
    Minimize               = 0x6,
    ShowMinimizedNotActive = 0x7,
    ShowCurrentNotActive   = 0x8,
    Restore                = 0x9,
    ShowDefault            = 0xA,
    ForceMinimize          = 0xB
}

0 Stimmen

Das Problem bei dieser Implementierung ist, dass man keine Befehlszeilenargumente von der zweiten Instanz zurück zur ersten geben kann. Für eine bessere Erklärung siehe hier .

0 Stimmen

Es sieht nicht so aus, als ob dies in der Frage verlangt wird. Wie auch immer, das wäre kein konsistentes Verhalten... eine Instanz, die beendet wird, sollte das Verhalten der bestehenden nicht ändern. Wenn Sie möchten, dass sich Ihre Anwendung anders verhält, schließen Sie den aktuellen Prozess und starten Sie einen neuen mit anderen Parametern.

0 Stimmen

Aber dieses Verhalten ist die Standardeinstellung von Office. Sie öffnen das erste Dokument per Doppelklick und ein neuer Prozess beginnt. Wenn Sie das zweite Dokument öffnen, wird es in der ersten Instanz ein Fenster erhalten.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X