Как мне сфокусировать чужое окно? - PullRequest
16 голосов
/ 14 января 2009

У меня есть приложение, в котором одновременно может быть открыт только один его экземпляр. Для обеспечения этого я использую этот код:

        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 (работает!):

    [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 ;-)

Ответы [ 6 ]

10 голосов
/ 14 января 2009

У меня была такая же проблема, и SwitchToThisWindow () работал лучше всего для меня. Единственное ограничение - у вас должна быть установлена ​​XP sp1. Я играл с SetForegroundWindow, ShowWindow, и у них обоих были проблемы с отображением окна.

3 голосов
/ 19 февраля 2015

C # эквивалент ответа Тома Юргенса. Работает как шарм для меня.

    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);
        }
    }
3 голосов
/ 25 января 2011

То же, что и 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
2 голосов
/ 14 января 2009

Полная сторона Примечание ...

Вы можете использовать

Process.GetProcessesByName(me.ProcessName) 

вместо зацикливания всех процессов, запущенных в системе ...

UPDATE

PInvoke Правила для такого рода вещей ...

2 голосов
/ 14 января 2009

Полагаю, вы захотите использовать SetForegroundWindow

MSDN Пример

0 голосов
/ 14 января 2009

Можете ли вы получить свойство MainWindowHandle объекта Process и отправить ему сообщение WM_USER, которое вы можете интерпретировать как «какой-то другой экземпляр хочет вывести меня на передний план».

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...