MSDN.WhiteKnight - Stack Overflow answers
Ответ на "c#. Winforms. Single-Instance и активация окна при повторном запуске"
Answer 832037
Дело в том, что у функции SetForegroundWindow в Windows есть некоторые ограничения. Изменить активное окно может только процесс, который уже владеет активным окном, у которого недавно было свернуто активное окно, в который недавно осуществлялся ввод с помощью клавиатуры или мыши, либо которому явно выдано разрешение на изменение активного окна с помощью AllowSetForegroundWindow (есть и другие случаи, см. документацию). Поэтому данная схема работает не всегда. Обходится это довольно просто (на Win7, по крайней мере), перед активацией окна сначала его свернуть и восстановить:
private void NamedPipeManager_ReceiveString(string obj) { main.WindowState = FormWindowState.Minimized; main.WindowState = FormWindowState.Normal; main.Activate(); }
Но в целом, вся схема с мьютексами и каналами для проверки единственности окна программы кажется слишком сложной и ненужной. То же самое можно реализовать гораздо проще, не упираясь в эти ограничения. Существующее окно программы можно найти через Process.MainWindowHandle, а для передачи командной строки использовать WM_COPYDATA:
using System; using System.IO; using System.Linq; using System.Collections.Generic; using System.ComponentModel; using System.Text; using System.Windows.Forms; using System.Diagnostics; using System.Runtime.InteropServices; namespace WindowsFormsTest1 { public partial class Form1 : Form { [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] static extern bool SetForegroundWindow(IntPtr hWnd); [DllImport("user32.dll")] static extern bool ShowWindow(IntPtr hWnd, int nCmdShow); const int ShowWindow_Restore = 9; [DllImport("user32.dll")] public static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, ref COPYDATASTRUCT lParam); [StructLayout(LayoutKind.Sequential)] public struct COPYDATASTRUCT { public IntPtr dwData; public int cbData; public IntPtr lpData; } const uint WM_COPYDATA = 0x004A; public Form1() { InitializeComponent(); Process this_process = Process.GetCurrentProcess(); //найти все процессы с таким же именем Process[] other_processes = Process.GetProcessesByName(this_process.ProcessName).Where(pr => pr.Id != this_process.Id).ToArray(); foreach (var pr in other_processes) { pr.WaitForInputIdle(1000); //на случай, если процесс еще не загрузился //берем первый процесс с окном IntPtr hWnd = pr.MainWindowHandle; if (hWnd == IntPtr.Zero) continue; //отправляем командную строку string command_line = "/activate"; var cds = new COPYDATASTRUCT(); cds.dwData = (IntPtr)1; cds.cbData = (command_line.Length + 1) * 2; cds.lpData = Marshal.StringToHGlobalUni(command_line); SendMessage(hWnd, WM_COPYDATA, IntPtr.Zero, ref cds); Marshal.FreeHGlobal(cds.lpData); //активируем окно и выходим ShowWindow(hWnd, ShowWindow_Restore); SetForegroundWindow(hWnd); Environment.Exit(0); } //если ничего не найдено, продолжаем работу } protected override void WndProc(ref Message m) { if (m.Msg == WM_COPYDATA) { COPYDATASTRUCT data = new COPYDATASTRUCT(); data = (COPYDATASTRUCT)Marshal.PtrToStructure(m.LParam, data.GetType()); textBox1.Text = Marshal.PtrToStringUni(data.lpData); } base.WndProc(ref m); } private void Form1_Load(object sender, EventArgs e) { textBox1.Focus(); textBox1.Select(); } } }
Content is retrieved from StackExchange API.
Auto-generated by ruso-archive tools.