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

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

發佈於 2018-07-24 06:19 更新於 2018-08-31 23:58

有些窗口天生就是爲了輔助其它程序而使用的,典型的如“輸入法窗口”。這些窗口不希望搶奪其它窗口的焦點。

有 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 位系統中需調用 GetWindowLongPtrSetWindowLongPtr,而 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
    }
}

運行這段代碼,可以發現,即時我們的窗口中文本框獲得了焦點,焦點其實依然在外面的程序中。(我們的文本框依然不會響應鍵盤輸入的。)


參考資料

本文會經常更新,請閱讀原文: https://walterlv.com/post/no-activate-window.html ,以避免陳舊錯誤知識的誤導,同時有更好的閱讀體驗。

本作品採用 知識共享署名-非商業性使用-相同方式共享 4.0 國際許可協議 進行許可。歡迎轉載、使用、重新發布,但務必保留文章署名 呂毅 (包含鏈接: https://walterlv.com ),不得用於商業目的,基於本文修改後的作品務必以相同的許可發佈。如有任何疑問,請 與我聯繫 ([email protected])

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章