OK, więc po raz ostatni (oby) odpowiadam w temacie jednej instancji aplikacji. Poniższy kod jest sklejony z kilku dostępnych na stackoverflow (głównie http://stackoverflow.com/questions/184084/how-to-force-c-sharp-net-app-to-run-only-one-instance-in-windows/11463450#11463450 i http://stackoverflow.com/questions/11065026/get-window-state-of-another-process).
Kod:
- przywróci pierwsze okno aplikacji o nazwie procesu identycznej z procesem sprawdzającym te dane;
- jeśli takiego okna nie znajdzie, a nie jest to jedyna instancja muteksu o podanej nazwie, wyświetli informację o nieznalezieniu procesu i nie pozwoli na uruchomienie aplikacji;
- poradzi sobie zarówno z oknem zminimalizowanym, jak i zmaksymalizowanym oraz o normalnym rozmiarze.
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows.Forms;
namespace SomeApplication
{
static class Program
{
[DllImport("USER32.DLL")]
public static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool GetWindowPlacement(IntPtr hWnd, ref WindowPlacement lpwndpl);
private enum ShowWindowCommands : int
{
ShowNormal = 1,
ShowMinimized = 2,
ShowMaximized = 3,
Show = 5,
Restore = 9
}
[Serializable]
[StructLayout(LayoutKind.Sequential)]
private struct WindowPlacement
{
public int length;
public int flags;
public ShowWindowCommands showCmd;
public System.Drawing.Point ptMinPosition;
public System.Drawing.Point ptMaxPosition;
public System.Drawing.Rectangle rcNormalPosition;
}
private static WindowPlacement GetPlacement(IntPtr hwnd)
{
WindowPlacement placement = new WindowPlacement();
placement.length = Marshal.SizeOf(placement);
GetWindowPlacement(hwnd, ref placement);
return placement;
}
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
bool createdNew = true;
using (Mutex mutex = new Mutex(true, "SomeApplication", out createdNew))
{
if (createdNew)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
else
{
var processFound = false;
Process current = Process.GetCurrentProcess();
foreach (Process process in Process.GetProcessesByName(current.ProcessName))
{
if (process.Id != current.Id)
{
var handle = process.MainWindowHandle;
var placement = GetPlacement(handle);
if (placement.showCmd == ShowWindowCommands.ShowMinimized) ShowWindow(handle, (int)ShowWindowCommands.Restore);
SetForegroundWindow(handle);
processFound = true;
}
}
if (!processFound) MessageBox.Show("Process not found, use genuine executable name."); // gtfo
}
}
}
}
}
Może ktoś pokusi się o napisanie wersji, która będzie działać niezależnie od zmiany nazwy procesu? Chodzi o postawienie czegoś w rodzaju "serwera" i odebrania sygnału z innej aplikacji.