93 lines
3.1 KiB
C#
93 lines
3.1 KiB
C#
using System;
|
|
|
|
namespace Notify.Interop;
|
|
|
|
/// <summary>
|
|
/// 把目标窗口拉回前台
|
|
///
|
|
/// Windows 限制后台进程抢焦点,这里用一套组合技绕过:ALT 键模拟 +
|
|
/// AttachThreadInput 把当前线程与前台/目标线程的输入队列挂接 +
|
|
/// SetWindowPos/BringWindowToTop/SwitchToThisWindow/SetForegroundWindow 多管齐下
|
|
/// </summary>
|
|
public static class WindowActivator
|
|
{
|
|
public static bool Activate(IntPtr hwnd)
|
|
{
|
|
if (hwnd == IntPtr.Zero || !Win32.IsWindow(hwnd))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
var root = Win32.GetAncestor(hwnd, Win32.GA_ROOT);
|
|
if (root != IntPtr.Zero)
|
|
{
|
|
hwnd = root;
|
|
}
|
|
|
|
var foreground = Win32.GetForegroundWindow();
|
|
var curThread = Win32.GetCurrentThreadId();
|
|
var fgThread = Win32.GetWindowThreadProcessId(foreground, out _);
|
|
var targetThread = Win32.GetWindowThreadProcessId(hwnd, out _);
|
|
var attachedForeground = false;
|
|
var attachedTarget = false;
|
|
|
|
try
|
|
{
|
|
// 最小化的先还原
|
|
if (Win32.IsIconic(hwnd))
|
|
{
|
|
Win32.ShowWindow(hwnd, Win32.SW_RESTORE);
|
|
}
|
|
|
|
// 模拟一次 ALT 抬起,满足 Windows 的"防焦点抢占"前置条件
|
|
Win32.keybd_event(Win32.VK_MENU, 0, 0, IntPtr.Zero);
|
|
Win32.keybd_event(Win32.VK_MENU, 0, Win32.KEYEVENTF_KEYUP, IntPtr.Zero);
|
|
|
|
if (fgThread != curThread)
|
|
{
|
|
attachedForeground = Win32.AttachThreadInput(curThread, fgThread, true);
|
|
}
|
|
|
|
if (targetThread != curThread && targetThread != fgThread)
|
|
{
|
|
attachedTarget = Win32.AttachThreadInput(curThread, targetThread, true);
|
|
}
|
|
|
|
Win32.AllowSetForegroundWindow(Win32.ASFW_ANY);
|
|
Win32.SetWindowPos(hwnd, IntPtr.Zero, 0, 0, 0, 0, Win32.SWP_NOMOVE | Win32.SWP_NOSIZE | Win32.SWP_SHOWWINDOW);
|
|
Win32.BringWindowToTop(hwnd);
|
|
Win32.SwitchToThisWindow(hwnd, true);
|
|
Win32.SetForegroundWindow(hwnd);
|
|
Win32.ShowWindow(hwnd, Win32.SW_SHOW);
|
|
|
|
if (Win32.GetForegroundWindow() != hwnd)
|
|
{
|
|
Win32.SetWindowPos(hwnd, Win32.HWND_TOPMOST, 0, 0, 0, 0,
|
|
Win32.SWP_NOMOVE | Win32.SWP_NOSIZE | Win32.SWP_SHOWWINDOW);
|
|
Win32.SetWindowPos(hwnd, Win32.HWND_NOTOPMOST, 0, 0, 0, 0,
|
|
Win32.SWP_NOMOVE | Win32.SWP_NOSIZE | Win32.SWP_SHOWWINDOW);
|
|
Win32.BringWindowToTop(hwnd);
|
|
Win32.SetForegroundWindow(hwnd);
|
|
}
|
|
|
|
return Win32.GetAncestor(Win32.GetForegroundWindow(), Win32.GA_ROOT) == hwnd;
|
|
}
|
|
catch
|
|
{
|
|
return false;
|
|
}
|
|
finally
|
|
{
|
|
if (attachedTarget)
|
|
{
|
|
Win32.AttachThreadInput(curThread, targetThread, false);
|
|
}
|
|
|
|
if (attachedForeground)
|
|
{
|
|
Win32.AttachThreadInput(curThread, fgThread, false);
|
|
}
|
|
}
|
|
}
|
|
}
|