正确的方式(在.NET中)将焦点切换到另一个应用程序

Jon*_*len 35 .net pinvoke process

这是我到目前为止:

    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
Run Code Online (Sandbox Code Playgroud)

它有两个问题.

  1. 有些人告诉我,SwitchToThisWindow已被删除.
  2. 如果应用程序B被最小化,则从用户的角度来看,此功能无声地失败.

那么这样做的正确方法是什么?

cae*_*say 36

获取窗口句柄(hwnd),然后使用此user32.dll函数:

VB.net声明:

Declare Function SetForegroundWindow Lib "user32.dll" (ByVal hwnd As Integer) As Integer 
Run Code Online (Sandbox Code Playgroud)

C#声明:

[DllImport("user32.dll")] public static extern int SetForegroundWindow(int hwnd) 
Run Code Online (Sandbox Code Playgroud)

一个考虑因素是,如果窗口最小化,这将不起作用,所以我编写了以下方法来处理这种情况.这是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);
    }
}
Run Code Online (Sandbox Code Playgroud)

使用该代码,就像设置适当的流程变量和调用一样简单 BringMainWindowToFront("processName");


Sim*_*ier 35

还有另一种方法,它使用了不为人知的UI Automation API:

AutomationElement element = AutomationElement.FromHandle(process.MainWindowHandle);
if (element != null)
{
    element.SetFocus();
}
Run Code Online (Sandbox Code Playgroud)

大多数情况下,如果可以切换到该窗口,这将有效.Windows(安全性,UAC,特定配置等)中存在许多限制,这些限制可能会阻止您更改最终用户的关注点.

  • .NET 4.5:AutomationElement位于UIAutomationClient中(在UIAutomationClient.dll中) (8认同)
  • 值得注意的是,如果窗口已被隐藏且没有任务栏图标,则此操作无效.(MainWindowHandle将为null) (2认同)

小智 7

在您的项目中创建一个新类并将以下代码复制粘贴到其中。

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

    }
}
Run Code Online (Sandbox Code Playgroud)

现在将以下代码复制粘贴到您需要的区域。

string procName = Process.GetCurrentProcess().ProcessName;
ProcessHelper.SetFocusToExternalApp(procName);
Run Code Online (Sandbox Code Playgroud)

在这里,您正在调用该函数将焦点移至其他应用程序的窗口。


小智 5

在VB.Net中,可以使用AppActivate函数。

Dim App As Process() = Process.GetProcessesByName("program.exe")
If App.Length > 0 Then
   AppActivate(App(0).Id)
End If
Run Code Online (Sandbox Code Playgroud)