Win32Api -- 使应用Always on top的几种方法

本文介绍几种使应用一直置于顶层的方法。

问题描述

优惠券网站 https://www.cps3.cn/

一般情况下,想要将应用置于顶层,设置其TopMost属性为true即可。对于多个设置了TopMost属性的应用,后激活的在上面。

但有的应用,比如全局的快捷操作工具条,它需要在所有应用之上,即使是设置了TopMost的应用。

解决思路

注意:使某个应用永远不会被其它应用覆盖,这本身是个伪命题。因为假如有两个程序(A和B)这样做,拖动两个窗口使它们重叠,这两个窗口中的一个必须在另一个之上,这在逻辑上是互相矛盾的。

所以应该尽量避免这种情况,如果非要这样做,本文提供如下几种办法实现(不要将两个这样的应用重叠,否则会不停将置顶)。

首先,该应用程序需要设置其TopMost属性为true,这样普通窗口本身就会在它下面。本文主要讨论该窗口如何置于设置了TopMost属性的窗口之上。

方案一:捕获WM_WINDOWPOSCHANGING消息

我们知道,使用Win32的SetWindowPos接口可以改变窗口的Z Order,可以猜测,当另外一个应用置顶时,我们的应用会改变其Z Order,因此,我们可以尝试捕获WM_WINDOWPOSCHANGING消息。

当窗口的大小、位置、Z序改变时,窗口会接收到WM_WINDOWPOSCHANGING消息,我们可以使用WndProc处理窗口消息。当捕获到该消息时,我们可以尝试将应用再次置顶。关键代码如下,测试可行,但不确定是否有副作用:

/// <summary>
/// 方案一:捕获WM_WINDOWPOSCHANGING消息,若无SWP_NOZORDER标志,则置顶
/// </summary>
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
    switch (msg)
    {
        case Win32Api.WM_WINDOWPOSCHANGING:
            Win32Api.WINDOWPOS wp = (Win32Api.WINDOWPOS)Marshal.PtrToStructure(
                lParam, typeof(Win32Api.WINDOWPOS));
            if ((wp.flags & Win32Api.SWP_NOZORDER) == 0)
                _ = SetTopMostLater(); // 不使用弃元编译器会发出警告
            break;
    }

    return IntPtr.Zero;
}

private async Task SetTopMostLater()
{
    await Task.Delay(300);
    var interopHelper = new WindowInteropHelper(this);
    Win32Api.SetWindowPos(interopHelper.Handle, Win32Api.HWND_TOPMOST, 0, 0, 0, 0, Win32Api.TOPMOST_FLAGS);
}

方案二:循环置顶

这个是比较容易想到的一个方案,每隔一定的时间给应用设置下TopMost,该方案也是可行的:

/// <summary>
/// 方案二:循环置顶
/// </summary>
/// <returns></returns>
private async Task SetTopMostLoop()
{
    while (true)
    {
        await Task.Delay(2000);
        var interopHelper = new WindowInteropHelper(this);
        Win32Api.SetWindowPos(interopHelper.Handle, Win32Api.HWND_TOPMOST, 0, 0, 0, 0, Win32Api.TOPMOST_FLAGS);
    }
}

方案三:使用钩子

思考一下,其实大部分情况下,使用鼠标或键盘等其它输入设备才会导致窗口的置顶被抢,因此可以使用全局钩子捕获输入事件,然后进行处理。

该方案是存在瑕疵的,因为存在不使用输入设备打开某个应用的情况,这种情况下置顶效果就会被新打开的置顶应用抢占。

// 方案三:当鼠标按下时置顶(仅考虑了鼠标)
private void MouseHook_OnMouseActivity(object sender, System.Windows.Forms.MouseEventArgs e)
{
    Console.WriteLine("mouse down......");
    _ = SetTopMostLater();
}

private MouseHook _mouseHook;

最后,本文是我对该问题想到的一些解决方案,Windows系统的任务管理器可以运行在所有应用的最上层,也许微软正是考虑到上文提到的伪命题,因此没有开放该接口吧,了解原理的小伙伴欢迎讨论。

本文三种方案的完整demo见GitHub,可以参考的链接(关于该话题的讨论较老了):链接一、链接二。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
如何设置让一个窗口总在最前(Exaware OnTop和PushPin)软件下载 Windows中打开一个新窗口或切换任务时,原有的活动窗口就会被它所覆盖。不过,像Winamp等软件,却有一个能让自己的操作窗口总在最前的功能,非常实用。其实,只要你安装了像ExaWare OnTop和PushPin这样的免费小软件,也一样可以让任意Windows操作窗口总在最前面,不让其他的窗口挡住它! 1.好用的ExaWare OnTop 下载并安装该软件后,双击桌面上的ExaWare OnTop 图标启动程序,我们看不到它的任何窗口界面,但在系统托盘上可以发现它的图标。单击该图标会弹出一个菜单,在这里列出了当前系统中所有窗口的标题。要想让某个窗口总在最前面,只要将鼠标移到相应的窗口标题项并点击鼠标(左右键均可)即可,如图所示。单击后该窗口标题前面的图标也相应地多了一个方框(如果没有图标则会显示一个对勾),表明该窗口已经设置成功。这时打开该窗口,再打开其他程序窗口,看看它是否一直总在其他窗口的前面而不被遮住?怎么样,是不是有种高高在上的感觉?要想取消 OnTop 状态,只要重复一遍上面的操作就可以了。 看到这里你是不是有一个疑问:如果同时将两个窗口设置为总在最前(Always OnTop)的状态,那将会发生什么事情呢?其实也很简单,如果两个(或多个)窗口同时处于总在最前的状态,那说明它们的地位平等,这时先激活谁谁就在最上面(和设置前一样看待)。另外还有一个问题需要注意:如果需要退出该软件,建议点击系统托盘上的软件图标并选择菜单中的“Exit and Restore”命令,这样在退出软件的同时可以恢复各个窗口的原始状态,以免给使用带来不便。 2.小巧的PushPin 相对于ExaWare OnTop 来说,PushPin 的体积更为小巧,只有区区的22KB 下载得到的是一个压缩包,由于它是一款绿色软件,我们只要直接将该压缩包解压缩到某个指定的目录下即可运行(主程序文件名为Pushpin.exe),同样看不到主程序窗口,只会发现系统托盘处多了一个图标。要想让某个操作窗口总在最前面,只要在其标题栏上(在任务栏按钮上也可)单击鼠标右键并从弹出的菜单中选择“Always on top”命令即可。要退出程序只需用鼠标右击系统托盘上的软件图标,并从弹出的菜单中选择“Remove”命令即可
The SetForegroundWindow Win32-API function is used to bring a window to the foreground and give it focus. However, it may not always work on Windows 7 due to certain security enhancements introduced in the operating system. One possible reason why SetForegroundWindow may fail on Windows 7 is because of the User Interface Privilege Isolation (UIPI) feature. UIPI restricts applications from sending messages to higher integrity level processes, which can prevent a lower integrity level process from bringing a higher integrity level window to the foreground. Another reason could be related to the focus-stealing prevention feature in Windows 7. This feature prevents applications from stealing focus from the user, which can be particularly useful in preventing malware from taking control of a user's system. To ensure that SetForegroundWindow works correctly on Windows 7, you can try the following: 1. Ensure that the window you are trying to bring to the foreground is not running with higher privileges than your application. 2. Use the AttachThreadInput API to attach the input queues of your application and the target window's thread before calling SetForegroundWindow. 3. Use the AllowSetForegroundWindow API to grant your application permission to bring the target window to the foreground. 4. Consider using the SetWindowPos API instead of SetForegroundWindow to adjust the position of the target window. If you continue to experience issues with SetForegroundWindow on Windows 7, you may need to consider alternative methods for achieving the same functionality.

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值