Правильный способ (в .NET) переключить фокус на другое приложение - PullRequest
34 голосов
/ 23 февраля 2010

Это то, что я имею до сих пор:

    Dim bProcess = Process.GetProcessesByName("By").FirstOrDefault
    If bProcess IsNot Nothing Then
        SwitchToThisWindow(bProcess.MainWindowHandle, True)
    Else
        Process.Start("C:\Program Files\B\B.exe")
    End If

У него две проблемы.

  1. Некоторые люди говорили мне, что SwitchToThisWindow запрещен.
  2. Если приложение B свернуто, с точки зрения пользователя эта функция молча завершается сбоем.

Так, как правильно это сделать?

Ответы [ 7 ]

35 голосов
/ 23 февраля 2010

Получите дескриптор окна (hwnd), а затем используйте эту функцию user32.dll:

Объявление VB.net:

Declare Function SetForegroundWindow Lib "user32.dll" (ByVal hwnd As Integer) As Integer 

C # объявление:

[DllImport("user32.dll")] public static extern int SetForegroundWindow(int hwnd) 

Одним из соображений является то, что это не будет работать, если окно свернуто, поэтому я написал следующий метод, который также обрабатывает этот случай. Вот код C #, для перехода на VB должно быть довольно просто.

[System.Runtime.InteropServices.DllImport("user32.dll")]
[return: System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.Bool)]
private static extern bool ShowWindow(IntPtr hWnd, ShowWindowEnum flags);

[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern int SetForegroundWindow(IntPtr hwnd);

private enum ShowWindowEnum
{
    Hide = 0,
    ShowNormal = 1, ShowMinimized = 2, ShowMaximized = 3,
    Maximize = 3, ShowNormalNoActivate = 4, Show = 5,
    Minimize = 6, ShowMinNoActivate = 7, ShowNoActivate = 8,
    Restore = 9, ShowDefault = 10, ForceMinimized = 11
};

public void BringMainWindowToFront(string processName)
{
    // get the process
    Process bProcess = Process.GetProcessesByName(processName).FirstOrDefault();

    // check if the process is running
    if (bProcess != null)
    {
        // check if the window is hidden / minimized
        if (bProcess.MainWindowHandle == IntPtr.Zero)
        {
            // the window is hidden so try to restore it before setting focus.
            ShowWindow(bProcess.Handle, ShowWindowEnum.Restore);
        }

        // set user the focus to the window
        SetForegroundWindow(bProcess.MainWindowHandle);
    }
    else
    {
        // the process is not running, so start it
        Process.Start(processName);
    }
}

Используя этот код, это будет так же просто, как установить соответствующие переменные процесса и вызвать BringMainWindowToFront("processName");

34 голосов
/ 17 сентября 2010

Существует еще один способ, который использует не очень известный API автоматизации пользовательского интерфейса:

AutomationElement element = AutomationElement.FromHandle(process.MainWindowHandle);
if (element != null)
{
    element.SetFocus();
}

В большинстве случаев это будет работать, если возможно переключиться на это окно. В Windows существует множество ограничений (безопасность, UAC, конкретная конфигурация и т. Д.), Которые могут помешать вам изменить фокус на конечного пользователя.

4 голосов
/ 19 июня 2012

Я использовал SetForegroundWindow, чтобы отобразить окно из другого приложения.

[DllImport("user32.dll")]
static extern bool SetForegroundWindow(IntPtr hWnd);

Как мне сфокусироваться на другом процессе из C #?

3 голосов
/ 10 октября 2014

В VB.Net вы можете использовать функцию AppActivate .

Dim App As Process() = Process.GetProcessesByName("program.exe")
If App.Length > 0 Then
   AppActivate(App(0).Id)
End If
3 голосов
/ 13 августа 2014

Создайте новый класс в своем проекте и скопируйте в него приведенный ниже код.

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;

namespace MyProject
{
    public class ProcessHelper
    {
        public static void SetFocusToExternalApp(string strProcessName)
        {
            Process[] arrProcesses = Process.GetProcessesByName(strProcessName);
            if (arrProcesses.Length > 0)
            {

                IntPtr ipHwnd = arrProcesses[0].MainWindowHandle;
                Thread.Sleep(100);
                SetForegroundWindow(ipHwnd);

            }
        }

    //API-declaration
    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern bool SetForegroundWindow(IntPtr hWnd);

    }
}

Теперь скопируйте и вставьте приведенный ниже код в нужную вам область.

string procName = Process.GetCurrentProcess().ProcessName;
ProcessHelper.SetFocusToExternalApp(procName);

Здесь вы вызываете функцию для фокусировки на окне другого приложения.

2 голосов
/ 08 мая 2013

Импорт:

Imports System.Runtime.InteropServices

Поместите это в модуль

<DllImport("user32.dll")> _
Private Function SetForegroundWindow(hWnd As IntPtr) As Boolean
End Function

Public Sub FocusWindow(ByVal ProcessName As String)
    Dim p As System.Diagnostics.Process = System.Diagnostics.Process.GetProcessesByName(ProcessName).FirstOrDefault
    If p IsNot Nothing Then
        SetForegroundWindow(p.MainWindowHandle)
        SendKeys.SendWait("~") ' maximize the application if it's minimized
    End If
End Sub

Использование:

FocusWindow("Notepad")

Источник: http://www.codeproject.com/Tips/232649/Setting-Focus-on-an-External-application#_rating

1 голос
/ 13 июня 2018

Эта работа для меня

[DllImport("user32.dll", SetLastError = true)]
static extern void SwitchToThisWindow(IntPtr hWnd, bool turnOn);
[STAThread]
        static void Main()
        {
            Process bProcess = Process.GetProcessesByName(processnamehere).FirstOrDefault() ;
            if (bProcess != null)
                    {
                        SwitchToThisWindow(bProcess.MainWindowHandle, true);
                    }
                GC.Collect();
        }   
...