.NET/C# 使窗口永不激活(No Activate 永不获得焦点)

2021-07-02 07:04

阅读:439

标签:lib   studio   ice   ptr   stack   targe   响应   激活   输入   

原文 .NET/C# 使窗口永不激活(No Activate 永不获得焦点)

有些窗口天生就是为了辅助其它程序而使用的,典型的如“输入法窗口”。这些窗口不希望抢夺其它窗口的焦点。

有 Win32 方法来解决这样的问题,WS_EX_NOACTIVATE 便是关键。


具体来说,是给窗口样式中额外添加一个 WS_EX_NOACTIVATE 位。

var handle = GetTheWindowHandle();
int exstyle = GetWindowLong(handle, GWL_EXSTYLE);
SetWindowLong(handle, GWL_EXSTYLE, exstyle | WS_EX_NOACTIVATE);

当然,这里需要用到 P/Invoke 平台调用,可以阅读 使用 PInvoke.net Visual Studio Extension 辅助编写 Win32 函数签名 了解快速生成平台调用方法签名的方法。

于是,我们将完整的窗口代码写完,是下面这样。

注意 64 位系统中需调用 GetWindowLongPtr 和 SetWindowLongPtr,而 32 位系统中是没有这两个方法的;在任何版本的 Windows 中都是这样。当然,64 位系统会为其上运行的 32 位进程模拟 32 位系统的环境。

using System;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interop;

namespace Walterlv.Demo
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            SourceInitialized += OnSourceInitialized;
        }
        
        private void OnSourceInitialized(object sender, EventArgs e)
        {
            var handle = new WindowInteropHelper(this).Handle;
            var exstyle = GetWindowLong(handle, GWL_EXSTYLE);
            SetWindowLong(handle, GWL_EXSTYLE, new IntPtr(exstyle.ToInt32() | WS_EX_NOACTIVATE));
        }

        #region Native Methods

        private const int WS_EX_NOACTIVATE = 0x08000000;
        private const int GWL_EXSTYLE = -20;

        public static IntPtr GetWindowLong(IntPtr hWnd, int nIndex)
        {
            return Environment.Is64BitProcess
                ? GetWindowLong64(hWnd, nIndex)
                : GetWindowLong32(hWnd, nIndex);
        }

        public static IntPtr SetWindowLong(IntPtr hWnd, int nIndex, IntPtr dwNewLong)
        {
            return Environment.Is64BitProcess
                ? SetWindowLong64(hWnd, nIndex, dwNewLong)
                : SetWindowLong32(hWnd, nIndex, dwNewLong);
        }

        [DllImport("user32.dll", EntryPoint = "GetWindowLong")]
        private static extern IntPtr GetWindowLong32(IntPtr hWnd, int nIndex);

        [DllImport("user32.dll", EntryPoint = "GetWindowLongPtr")]
        private static extern IntPtr GetWindowLong64(IntPtr hWnd, int nIndex);

        [DllImport("user32.dll", EntryPoint = "SetWindowLong")]
        private static extern IntPtr SetWindowLong32(IntPtr hWnd, int nIndex, IntPtr dwNewLong);

        [DllImport("user32.dll", EntryPoint = "SetWindowLongPtr")]
        private static extern IntPtr SetWindowLong64(IntPtr hWnd, int nIndex, IntPtr dwNewLong);

        #endregion
    }
}

运行这段代码,可以发现,即时我们的窗口中文本框获得了焦点,焦点其实依然在外面的程序中。(我们的文本框依然不会响应键盘输入的。)

技术分享图片


参考资料

  • c# - Not take focus, but allow interaction? - Stack Overflow
  • Extended Window Styles - Microsoft Docs
  • GetWindowLongPtr function (Windows)
  • SetWindowLongPtr function (Windows)

本文会经常更新,请阅读原文: https://walterlv.com/post/no-activate-window.html ,以避免陈旧错误知识的误导,同时有更好的阅读体验。

.NET/C# 使窗口永不激活(No Activate 永不获得焦点)

标签:lib   studio   ice   ptr   stack   targe   响应   激活   输入   

原文地址:https://www.cnblogs.com/lonelyxmas/p/9933320.html


评论


亲,登录后才可以留言!