.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 位系統中需調用 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 ,以避免陳舊錯誤知識的誤導,同時有更好的閱讀體驗。
本作品採用 知識共享署名-非商業性使用-相同方式共享 4.0 國際許可協議 進行許可。歡迎轉載、使用、重新發布,但務必保留文章署名 呂毅 (包含鏈接: https://walterlv.com ),不得用於商業目的,基於本文修改後的作品務必以相同的許可發佈。如有任何疑問,請 與我聯繫 ([email protected]) 。