Как настроить внешнее окно?
У меня есть приложение, которое может иметь только один экземпляр сам по себе. Чтобы обеспечить соблюдение этого, я использую этот код:
System.Diagnostics.Process[] myProcesses = System.Diagnostics.Process.GetProcesses();
System.Diagnostics.Process me = System.Diagnostics.Process.GetCurrentProcess();
foreach (System.Diagnostics.Process p in myProcesses)
{
if (p.ProcessName == me.ProcessName)
if (p.Id != me.Id)
{
//if already running, abort this copy.
return;
}
}
//launch the application.
//...
Он отлично работает. Мне также хотелось бы, чтобы он мог сфокусировать форму уже работающей копии. То есть, прежде чем возвращаться, я хочу привести другой экземпляр этого приложения на передний план.
Как это сделать?
Re: SetForeGroundWindow:
SetForeGroundWindow работает, до точки:
[System.Runtime.InteropServices.DllImport("user32.dll")]
public static extern bool SetForegroundWindow(IntPtr hWnd);
//...
if (p.Id != me.Id)
{
//if already running, focus it, and then abort this copy.
SetForegroundWindow(p.MainWindowHandle);
return;
}
//...
Это приносит окно на передний план, если оно не минимизировано. Потрясающие.
Однако, если окно минимизировано, оно остается минимальным.
Он должен свести к минимуму.
Решение через SwitchToThisWindow (Works!):
[System.Runtime.InteropServices.DllImport("user32.dll")]
public static extern void SwitchToThisWindow(IntPtr hWnd, bool fAltTab);
[STAThread]
static void Main()
{
System.Diagnostics.Process me = System.Diagnostics.Process.GetCurrentProcess();
System.Diagnostics.Process[] myProcesses = System.Diagnostics.Process.GetProcessesByName(me.ProcessName);
foreach (System.Diagnostics.Process p in myProcesses)
{
if (p.Id != me.Id)
{
SwitchToThisWindow(p.MainWindowHandle, true);
return;
}
}
//now go ahead and start our application ;-)
Ответы
Ответ 1
У меня была та же проблема, и SwitchToThisWindow() работал лучше для меня. Единственное ограничение заключается в том, что вы должны установить XP sp1. Я играл с SetForegroundWindow, ShowWindow, и у них обоих были проблемы с отображением окна.
Ответ 2
То же, что и OP, я обнаружил, что только SetForegroundWindow
недостаточно, когда окно было сведено к минимуму. Поскольку я не хотел использовать SwitchToThisWindow
, я выбрал ShowWindow
, а затем SetForegroundWindow
.
Хорошо работает для меня!
private const SW_SHOWNORMAL = 1
<DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
Private Function ShowWindow(ByVal hwnd As IntPtr, ByVal nCmdShow As integer) As Boolean
End Function
<DllImport("user32.dll", SetLastError:=True)> _
Private Function SetForegroundWindow(ByVal hwnd As IntPtr) As Boolean
End Function
Sub SetForeground()
Dim processes As Process() = Process.GetProcessesByName("myprocess")
For Each p as Process in processes
ShowWindow(p.MainWindowHandle, SW_SHOWNORMAL)
SetForegroundWindow(p.MainWindowHandle)
Next
End Sub
Ответ 3
Я считаю, что вы захотите использовать SetForegroundWindow
Пример MSDN
Ответ 4
Полное боковое примечание...
Вы можете использовать
Process.GetProcessesByName(me.ProcessName)
вместо того, чтобы перебирать все процессы, запущенные в системе...
UPDATE
PInvoke Правила для такого рода вещей...
Ответ 5
С# эквивалент ответа Тома Юргенса. Работает как прелесть для меня.
private const int SW_SHOWNORMAL = 1;
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern bool ShowWindow(IntPtr hwnd, int nCmdShow);
[DllImport("user32.dll", SetLastError = true)]
private static extern bool SetForegroundWindow(IntPtr hwnd);
public void SetForeground()
{
Process[] processes = Process.GetProcessesByName("process name");
foreach (Process p in processes) {
ShowWindow(p.MainWindowHandle, SW_SHOWNORMAL);
SetForegroundWindow(p.MainWindowHandle);
}
}
Ответ 6
Можете ли вы захватить свойство MainWindowHandle объекта Process и отправить ему сообщение WM_USER, которое вы можете интерпретировать как "какой-то другой экземпляр хочет вывести меня на передний план".