【问题标题】:Correct way (in .NET) to switch the focus to another application将焦点切换到另一个应用程序的正确方法(在 .NET 中)
【发布时间】:2011-01-19 21:49:29
【问题描述】:

这是我目前所拥有的:

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 最小化,从用户的角度来看,此功能会静默失败。

那么正确的做法是什么?

【问题讨论】:

标签: .net process pinvoke


【解决方案1】:

获取窗口句柄(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");

【讨论】:

  • 为什么将其声明为 Integer 而不是 IntPtr?
  • 它似乎不起作用。你能告诉我如何结合原始问题中的代码使用它吗?
  • SetActiveWindow 的返回值为零,表示错误。但我也得到了 GetLastWin32Error 的 0,这表示成功。知道下一步该往哪里看吗?
  • 对于ShowWindow,我需要传递bProcess.MainWindowHandle。真正令人沮丧的是,您的代码可以在除我需要的应用程序之外的所有应用程序上运行。
  • Int32 作为句柄在 64 位上无法正常工作。它只是似乎可以工作,因为您使用的是 32 位机器或操作系统。 IntPtr 被定义为与操作系统的位数相同,因此在 64 位操作系统上运行将为您提供 64 位 IntPtr。
【解决方案2】:

还有另一种方式,它使用了不知名的 UI 自动化 API:

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

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

【讨论】:

  • +1 用于突出一个鲜为人知的技术。非常好,感谢您扩展我的知识。
  • .NET 4.5:AutomationElement 在 UIAutomationClient 中(在 UIAutomationClient.dll 中)
  • 值得注意的是,如果窗口已被隐藏并且没有任务栏图标,这将不起作用。 (MainWindowHandle 将为空)
  • 感谢@teynon 的提醒,但只是为了勤奋,AutomationElement 似乎从 .NET 3.0 开始就存在:msdn.microsoft.com/en-us/library/…
  • 谢谢!真的帮了大忙 :) 比我使用的 SetForegroundWindow 好得多
【解决方案3】:

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

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

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

【讨论】:

    【解决方案4】:

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

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

    【讨论】:

      【解决方案5】:

      我使用 SetForegroundWindow 使来自另一个应用程序的窗口出现。

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

      How can I give another Process focus from C#?

      【讨论】:

        【解决方案6】:

        进口:

        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

        【讨论】:

          【解决方案7】:

          这对我有用

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

          【讨论】:

            【解决方案8】:

            以下对我有用,当我尝试使用从以下代码获得的exeAdministrator 身份运行 SQL Server Management Studio 和 Visual Studio 等应用程序时。

            切换助手

            public class ToggleHelper
            {
                [System.Runtime.InteropServices.DllImport("user32.dll")]
                [return: System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.Bool)]
                private static extern bool ShowWindow(IntPtr hWnd, EnumForWindow enumVal);
            
                [System.Runtime.InteropServices.DllImport("user32.dll")]
                private static extern int SetForegroundWindow(IntPtr hwnd);
            
                private enum EnumForWindow
                {
                    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 SetForeGroundMainWindowHandle(string processName)
                {
            
                    Console.WriteLine("SetForeGroundMainWindowHandle Called - for "+ processName);
                    Process p = Process.GetProcessesByName(processName).FirstOrDefault();
            
                    if (p != null)
                    {
                        Console.WriteLine(p.MainWindowHandle.ToString());
                        ShowWindow(p.MainWindowHandle, EnumForWindow.Restore);
                        System.Threading.Thread.Sleep(5000);
                        ShowWindow(p.MainWindowHandle, EnumForWindow.ShowMaximized);
                        //System.Threading.Thread.Sleep(5000);
                        SetForegroundWindow(p.MainWindowHandle);
                    }
                    else
                    {
                        Process.Start(processName);
                    }
                }
            }
            

            客户

            class Program
            {
                static void Main(string[] args)
                {
                    //RUN AS Administrator
                    var y = Process.GetProcesses().Where(pr => pr.MainWindowHandle != IntPtr.Zero);
                    foreach (Process proc in y)
                    {
                        Console.WriteLine(proc.ProcessName);
                    }
            
                    ToggleHelper t = new ToggleHelper();
            
                    int a = 0;
                    while (a <= 1)
                    {
                        t.SetForeGroundMainWindowHandle("Ssms");
                        System.Threading.Thread.Sleep(30000);
                        t.SetForeGroundMainWindowHandle("devenv");
                        System.Threading.Thread.Sleep(18000);
                    }
                    Console.ReadLine();
                }
            }
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2016-01-09
              • 1970-01-01
              • 2012-11-02
              • 2021-12-25
              • 1970-01-01
              • 1970-01-01
              • 2021-12-04
              • 2014-05-07
              相关资源
              最近更新 更多