【问题标题】:Manually activating a WPF window only works correctly when debugging in Visual Studio只有在 Visual Studio 中进行调试时,手动激活 WPF 窗口才能正常工作
【发布时间】:2020-07-16 01:51:52
【问题描述】:

我正在使用SetWindowsHookEx 注册一个全局热键,该热键应该可以激活我的 WPF 窗口并将其置于最前面。

我发现 3 个不同的函数似乎都实现了相同的目标,Window.ActivateSwitchToThisWindowSetForegroundWindow。我注意到,在 Visual Studio 中调试时,使我的窗口成为焦点的所有 3 种方法的行为都符合预期,但是当编译的程序在 VS 调试器之外运行时未能正确激活它。

I created a small example project 来说明问题。该应用程序只显示窗口的Activated/DeactivatedGotKeyboardFocus/LostKeyboardFocus 事件,以及它捕获的最后一个键。它将3种不同的激活方法绑定到全局热键1-3

下面是两个带有和不带有调试模式的应用程序的 GIF。两次我都使用全局热键从当前聚焦的记事本窗口切换到我的应用程序,然后只需按一些键。

两个窗口都接收ActivatedGotKeyboardFocus 事件,但只有在调试模式下,应用程序才会真正接收按键。在没有调试模式的情况下运行时,标题栏也不会从灰色变为黑色,这表明该窗口从未真正激活过。

在 VS 中运行

在 VS 之外运行

【问题讨论】:

    标签: c# wpf windows visual-studio .net-core


    【解决方案1】:

    在问这个之前,我忘了专门搜索有关 SetForegroundWindow 函数的问题,所以我错过了两个基本相同问题的问题。

    The first question 有两个高度赞成的答案,基本上使用相同的 hack,这在技术上是可行的,但不是一个可行的解决方案。使用keybd_event(0, 0, 0, 0) 模拟Keys.NONE 按下大约有半秒的延迟,并且由于某种原因还会触发 Nvidia Shadowplay 开始录制。 (这可能是 Nvidia 错误地将 Keys.NONE 解释为他们的热键之一)。

    A very recent answer on the second question 似乎是使用线程关联的正确解决方案。这是基于 C++ 示例的工作 C# 代码:

    [DllImport("user32.dll")]
    static extern uint GetWindowThreadProcessId(IntPtr hWnd, IntPtr ProcessId);
    
    [DllImport("kernel32.dll")]
    static extern uint GetCurrentThreadId();
    
    [DllImport("user32.dll")]
    static extern bool AttachThreadInput(uint idAttach, uint idAttachTo,  bool fAttach);
    
    [DllImport("user32.dll", SetLastError = true)]
    static extern bool BringWindowToTop(IntPtr hWnd);
    
    [DllImport("user32.dll")]
    private static extern int ShowWindow(IntPtr hWnd, uint Msg);
    
    [DllImport("user32.dll")]
    static extern IntPtr GetForegroundWindow();
    
    public static void ForceForegroundWindow(IntPtr hwnd)
    {
        uint windowThreadProcessId = GetWindowThreadProcessId(GetForegroundWindow(), IntPtr.Zero);
        uint currentThreadId = GetCurrentThreadId();
        uint CONST_SW_SHOW = 5;
        AttachThreadInput(windowThreadProcessId, currentThreadId, true);
        BringWindowToTop(hwnd);
        ShowWindow(hwnd, CONST_SW_SHOW);
        AttachThreadInput(windowThreadProcessId, currentThreadId, false);
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-06
      相关资源
      最近更新 更多