V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
phpfpm
V2EX  ›  Windows

所以 window tray 的这个 bug,从 win95 一直延续到 win11?

  •  
  •   phpfpm · 2022-01-28 23:46:42 +08:00 · 4707 次点击
    这是一个创建于 1059 天前的主题,其中的信息可能已经有所发展或是发生改变。

    一个在 tray 里面的程序,如果被 kill 掉没有 gracefully 退出,那么就会一直残留在 tray

    喵喵喵??? M$觉得这个是个 feature 么????

    18 条回复    2022-01-30 02:57:27 +08:00
    Osk
        1
    Osk  
       2022-01-29 00:49:31 +08:00
    想不到是祖传 bug, 鼠标晃一下就能消失, 不过有时很干扰.
    moen
        2
    moen  
       2022-01-29 00:51:34 +08:00   ❤️ 3
    严格上说这是机制的问题,不算 bug 。Notification icon 的创建和删除都是由应用程序自己 Push 给 explorer.exe ,但 explorer.exe 方面并没有设计一套 Pull 机制来主动了解 notification icon 所属的进程是否存在。所以进程崩溃了没法自行删除,就一直显示在那里了。而 explorer.exe 崩溃后 notification icon 不会重建也是因为这套机制导致的

    至于为什么一直不加我不知道
    imn1
        3
    imn1  
       2022-01-29 03:16:00 +08:00
    我自己写的一个 GUI 程序,测试时试过残留了几十个图标,每运行就生成一个,崩了就留下……
    kkocdko
        4
    kkocdko  
       2022-01-29 06:14:26 +08:00 via Android
    @moen 但是鼠标移上去就消失了,我对 windows 开发不熟悉,推测这大概是 mouseover ,然后向应用请求获得 tooltips ,结果发现没有回应,就知道应用推出了。

    那为什么不能隔一段时间轮询呢?难道是历史遗留问题,怕某些应用获取一次 tooltips 要花很多时间?或者某些应用依赖这种行为?
    geelaw
        5
    geelaw  
       2022-01-29 07:45:09 +08:00   ❤️ 12
    首先,那个东西叫“通知区域”,不叫 tray 。即使你认为 tray 来自于早期代码里的命名,tray 也是指整个任务栏。

    这个问题的成因是通知区域图标是程序通知任务栏创建的,崩溃时程序没有通知删除,所以不会立刻消失。

    鼠标放上去会消失是因为 Explorer 会给图标对应的窗口发消息,如果窗口句柄已经无效,则会删除图标——注意窗口句柄是 USER 句柄,因此既没有计数也会复用,在极限情况下可能新程序被分配到已经崩溃程序使用过的句柄,导致新程序莫名其妙收到消息。

    Explorer 崩溃重启后程序需要重新添加图标,获取这一信息的方法是注册“任务栏创建好了”消息。

    为什么不能轮询——因为不存在一个“心跳”消息,也不应该随便给窗口发送消息(虽然理论上可以注册一个新名字,这样任意窗口都不会对该消息有特殊反应才对),也不应该轮询(性能问题)。

    这个问题显然是可以解决的,比如任务栏上列举窗口的按钮可以对崩溃立刻作出反应,这个变化是 USER 监控,并发送 WM_SHELL_* 消息给任务栏的。然而通知区域图标并不是 USER 概念而是 shell 概念(只存在于 explorer.exe 进程中),虽然可以提升到 USER 概念实现之,估计是不值得吧( USER 是 per-session 级别的,可以容纳的句柄数量也相当有限)。

    更好的解决方法是——不要崩溃。

    类似的问题也存在于 Application Desktop Toolbar 。还有更多设计 bug 导致 shell 的一些部分需要两次操作才能刷新( COM categories 、shellnew 等)。
    yulon
        6
    yulon  
       2022-01-29 07:48:54 +08:00
    进程创建销毁的事件依赖内核态,所以内核资源比如文件网络都可以自动释放,你要监控就得写个驱动。

    GUI 资源一般是用户态的窗口消息管理的,他就是逼你正确处理窗口消息,不要越过 GUI 直接终止进程。

    既然已经有事件的方法了,再加个轮询就显得有点脏,当然这都是设计问题,人家就是这么规定的。
    ysc3839
        7
    ysc3839  
       2022-01-29 08:14:55 +08:00
    @geelaw 一种可行的方案是检测窗口对应的进程,这样不需要轮询,也不会有复用问题,缺点是没法解决进程没退出,窗口关闭但忘记删除 notification icon 的情况。
    caocong
        8
    caocong  
       2022-01-29 09:35:27 +08:00
    或许微软觉得这问题是应用的问题不是他的问题
    coolcfan
        9
    coolcfan  
       2022-01-29 10:07:30 +08:00
    网易 UU 正常点退出都会留图标在通知区域……
    geelaw
        10
    geelaw  
       2022-01-29 10:37:08 +08:00 via iPhone
    @ysc3839 #7 这是不行的,因为通知区域图标关联的窗口可能是高权限进程(或者另一个非管理员用户的进程),窗口消息仍然可以送达( Explorer 有 UIAccess ),但 Explorer 无权访问该进程。此外关联窗口可以变更,要恰当实现等待进程结束还是挺复杂的(需要用 WaitForMultipleObjects 技巧)。
    imn1
        11
    imn1  
       2022-01-29 12:24:00 +08:00
    @ysc3839 #7
    不一定是主进程创建的图标,引申:同一个程序也可以创建多个图标(例如火绒),这样要检查的可能太多了

    @coolcfan #9
    没用过这个,但我怀疑有驻留程序,只是主窗口关闭而已,“国产”很多类似情况,如迅雷、百度云管家
    dandycheung
        12
    dandycheung  
       2022-01-29 14:43:10 +08:00 via Android
    @geelaw 没有查资料,凭记忆瞎聊两句。1. 通知区域自从出现就是叫 tray ,当时翻译过来多数译作“托盘”。2. 用 TaskbarCreated 字符串注册出来是消息是后加的,不是一开始就有。3. 不要崩溃结局不了所有问题,有时候是被别人杀死的。4. 还有,有一个 Windows 消息,叫 WM_NULL ,似乎真需要的话,可以废物利用一下。
    CallMeReznov
        13
    CallMeReznov  
       2022-01-29 15:30:29 +08:00
    LxnChan
        14
    LxnChan  
       2022-01-29 16:40:07 +08:00
    @imn1 俺也一样
    @kkocdko 这个应该就是刻意没有做轮询,本身删除托盘图标的操作就是应该由程序本身发起而不是系统去做,一是性能问题二是万一当前 explorer 没有权限访问该程序(也可能是服务)就误以为该程序已经关闭甚至 explorer 直接崩溃
    @CallMeReznov 草哈哈哈
    ysc3839
        15
    ysc3839  
       2022-01-29 22:27:39 +08:00 via Android
    @geelaw 印象中 OpenProcess SYNCHRONIZE 好像不受权限限制吧?关联窗口变更后监视新窗口对应的进程就行了。
    @imn1 我没明白这是什么问题。
    @dandycheung 你的说法是错的,自从出现就是 Shell Notify Icon 。这篇文章 https://devblogs.microsoft.com/oldnewthing/20030910-00/?p=42583 也给出了一些理由。
    imn1
        16
    imn1  
       2022-01-29 23:08:50 +08:00
    @ysc3839 #15
    简单说,就是窗口、trayicon 、进程不是唯一对应的,例如主进程带出两个子进程,一个创建窗口,一个创建 trayicon……以此类推,还可能有第二、第三……窗口,第二、第三……trayicon ,这样检测其中某个窗口并不能确定它对应的 trayicon
    ysc3839
        17
    ysc3839  
       2022-01-29 23:18:03 +08:00 via Android
    @imn1 只需要监测接收 icon 消息的窗口所属的进程就行了呀,跟主进程子进程以及它们创建了多少窗口什么的都没关系。
    FrankHB
        18
    FrankHB  
       2022-01-30 02:57:27 +08:00
    进来就盲猜这个问题,果然……

    就算不是 feature ,怕是也周知到能当作 feature 了。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   881 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 19:57 · PVG 03:57 · LAX 11:57 · JFK 14:57
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.