SetForegroundWindow仅在Visual Studio打开时有效

21

我正在尝试使用C#将进程窗口设置为前台/焦点(在进行此操作时,应用程序没有焦点),因此我正在使用user32.dll中的static extern bool SetForegroundWindow(IntPtr hWnd)方法:

[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool SetForegroundWindow(IntPtr hWnd); 
public void setFocus()
{
    SetForegroundWindow(process.MainWindowHandle);       
}
一切都正常运行,但前提是我必须打开Visual Studio 2008,即使不用VS08启动应用程序,只需打开项目即可。一旦关闭项目,我的应用程序就无法将其他窗口设置到前景。唯一的结果是在任务栏中,其他窗口被蓝色突出显示。当我再次使用VS08打开我的项目时,它可以正常工作。我完全不知道为什么会这样...我认为问题可能是无法导入dll,但如果是这样的话,窗口就不会被突出显示了,而且其他win32函数(例如static extern bool ShowWindow(IntPtr hWnd, IntPtr status);)甚至在关闭项目后也能正常工作。有关此问题的任何解决方法或提示吗?编辑:我阅读了该函数的注释,并想到我的应用程序没有焦点,所以我尝试了这个:
[DllImport("user32.dll")]
static extern bool SetForegroundWindow(IntPtr hWnd);
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("user32.dll")]
static extern bool AllowSetForegroundWindow(int procID);
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll", SetLastError = true)]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId); 
public void setAUTFocus()
{
    IntPtr hWnd = GetForegroundWindow();
    uint processID = 0;
    uint threadID = GetWindowThreadProcessId(hWnd, out processID);
    int intID = (int)processID;
    AllowSetForegroundWindow(intID);
    SetForegroundWindow(process.MainWindowHandle); 
}        

现在我正在寻找当前具有焦点的窗口进程,并为该窗口设置AllowSetForegroundWindow,并尝试将焦点设置在我的窗口上。但是问题依旧,当我在VS中打开项目时,它可以正常工作,如果没有则只会在任务栏中出现突出显示。

在我的应用程序运行期间,我可以打开/关闭VS项目,当它打开时,一切正常,当它关闭时,就无法正常工作了,在运行我的应用程序时我没有与VS项目进行任何交互。说实话,我不明白。


1
请查看SetForeground窗口文档中的注释http://msdn.microsoft.com/en-us/library/windows/desktop/ms633539%28v=vs.85%29.aspx - Antonio Bakula
所以在尝试将另一个窗口置于前台时,我必须先调用AllowSetForegroundWindow函数,并提供处于焦点的窗口的进程ID吗? - dontcare
如果这不是答案,为什么在Visual Studio项目打开时它能够工作,当前的前景窗口从未是Visual Studio呢? - dontcare
这不是答案,我只是评论以引起你对那个问题的注意。 - Antonio Bakula
由于在此平台上不支持检索有关本地进程的信息,因此此方法无法用于UWP。 - der_michael
2个回答

31

在互联网上搜寻了几天之后,我找到了一种可能的简单解决方案来使SetForegroundWindow在Windows 7上工作:在调用SetForegroundWindow之前按下Alt键。

public static void ActivateWindow(IntPtr mainWindowHandle)
    {
        //check if already has focus
        if (mainWindowHandle == GetForegroundWindow())  return;

        //check if window is minimized
        if (IsIconic(mainWindowHandle))
        {
            ShowWindow(mainWindowHandle, Restore);
        }

        // Simulate a key press
        keybd_event((byte)ALT, 0x45, EXTENDEDKEY | 0, 0);

        //SetForegroundWindow(mainWindowHandle);

        // Simulate a key release
        keybd_event((byte)ALT, 0x45, EXTENDEDKEY | KEYUP, 0);

        SetForegroundWindow(mainWindowHandle);
    }

而且还有win32api导入

  private const int ALT = 0xA4;
  private const int EXTENDEDKEY = 0x1;
  private const int KEYUP = 0x2;
  private const uint Restore = 9;

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

  [DllImport("user32.dll")]
  private static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, int dwExtraInfo);

  [DllImport("user32.dll")]
  [return: MarshalAs(UnmanagedType.Bool)]
  private static extern bool IsIconic(IntPtr hWnd);

  [DllImport("user32.dll")]
  private static extern int ShowWindow(IntPtr hWnd, uint Msg);

  [DllImport("user32.dll")]
  private static extern IntPtr GetForegroundWindow();

1
为什么需要按Alt键? - Justin Dearing
3
如果您不模拟Alt键,则setforgroundwindow将无法正常工作。您想要切换到的程序将在任务栏中闪烁但不会进入前台。当您从Visual Studio调试运行程序时,setforgroundwindow可以正常工作。 - iulian3000
1
谢谢你的回答。顺便说一下,这个行为非常奇怪。我很乐意得到一个详细的解释。 - ReMinoer
抱歉,没有在Windows 10上进行测试。 - iulian3000
2
它适用于Windows 10,而且你甚至不需要模拟按下alt键,只需松开即可。 - Raymond Holmboe
1
对我来说,在Windows 11 (22H2) 上唯一有效的解决方案。诀窍就是使用ALT键,而且只模拟ALT_UP键才有效。谢谢。 - undefined

16

我在发送Alt键时遇到问题,当我选择enter键时,它会强制打开窗口菜单(而不是我想要的OK按钮)。

这对我有用:

public static void ActivateWindow(IntPtr mainWindowHandle)
{
    //check if already has focus
    if (mainWindowHandle == GetForegroundWindow())  return;

    //check if window is minimized
    if (IsIconic(mainWindowHandle))
    {
        ShowWindow(mainWindowHandle, Restore);
    }

    // Simulate a key press
    keybd_event(0, 0, 0, 0);

    SetForegroundWindow(mainWindowHandle);
}

1
keybd_event(0, 0, 0, 0); = Keys.NONE 在Windows 7中被内部过滤掉了。然而,在Windows 10之后,它不再被Windows过滤掉,并对应用程序产生了意外的影响。因此,如果您真的确定需要使用它,请注意这一点。 - Ishan Pandya

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接