今天遇到了一个很奇怪、也很烦人的 Windows 桌面问题。
屏幕上突然出现了一个浅黄色背景、只有 “Close” 字样的小方框。
它看起来像一个普通的提示框,但行为却一点也不普通:
- 长按它,无法拖动;
- 右键点击,没有任何反应;
- 按
Win + D回到桌面,它依然悬浮在最前面; - 打开任何窗口,它仍然压在所有窗口之上;
- 按
Win + Tab新建一个虚拟桌面,它竟然还会出现在新的桌面里; - 我完全不知道它到底是哪一个软件留下来的。

我是怎么描述问题的#
我给出的描述大致是:
电脑屏幕上出现了一个黄色背景的 “Close”。长按无法拖动,也无法右键点击。我想知道这是哪个软件留下的。
我使用
Win + D回到桌面,它依然在最前面;无论打开任何窗口,它都保持置顶。更奇怪的是,我用
Win + Tab新建虚拟桌面之后,它依然出现在新的桌面上。
现在回头看,我觉得这次问题能够很快被定位,一个很重要的原因就是:我没有只说“电脑上有个奇怪的框”,而是把它的行为特征一起描述出来了。
ChatGPT 后来也特别肯定了这一点。
Win + D 无法让它消失、普通窗口盖不住它、切换虚拟桌面后仍然存在——这些信息实际上已经排除了很多普通窗口的可能性,并把范围缩小到了 Topmost 悬浮层、Overlay、Tooltip 或特殊工具窗口。
这也是我这次提问做得比较对的地方之一:尽量描述“现象”,而不是急着替现象下结论。
ChatGPT 给出的判断#
ChatGPT 根据这些现象,判断它更像是某个程序创建出来的:
始终置顶的悬浮窗口、Overlay,或者工具提示窗口。
它首先推荐我使用微软 Sysinternals 的 Process Explorer,通过 “Find Window’s Process” 准星直接拖到这个 Close 上,从而定位创建窗口的进程。
不过我并没有下载 Process Explorer。
ChatGPT 同时还给了我另一个方案:
只使用 Windows 自带的 PowerShell,通过鼠标所在位置获取窗口句柄,再根据窗口句柄查询所属进程。
这个方案正合我意。
完整 PowerShell 脚本#
下面就是我实际执行的完整脚本。
运行之后会等待 3 秒。在这 3 秒内,只需要把鼠标移动到那个异常的 Close 提示框上,不需要点击。
展开查看完整 PowerShell 脚本
Add-Type @"
using System;
using System.Text;
using System.Runtime.InteropServices;
public class WinDetect {
[StructLayout(LayoutKind.Sequential)]
public struct POINT {
public int X;
public int Y;
}
[DllImport("user32.dll")]
public static extern bool GetCursorPos(out POINT lpPoint);
[DllImport("user32.dll")]
public static extern IntPtr WindowFromPoint(POINT Point);
[DllImport("user32.dll")]
public static extern IntPtr GetAncestor(IntPtr hwnd, uint gaFlags);
[DllImport("user32.dll")]
public static extern uint GetWindowThreadProcessId(
IntPtr hWnd,
out uint lpdwProcessId
);
[DllImport("user32.dll", CharSet=CharSet.Unicode)]
public static extern int GetWindowText(
IntPtr hWnd,
StringBuilder lpString,
int nMaxCount
);
[DllImport("user32.dll", CharSet=CharSet.Unicode)]
public static extern int GetClassName(
IntPtr hWnd,
StringBuilder lpClassName,
int nMaxCount
);
}
"@
Write-Host "3秒内把鼠标移动到黄色 Close 上,不要点击..."
Start-Sleep -Seconds 3
$pt = [WinDetect+POINT]::new()
[void][WinDetect]::GetCursorPos([ref]$pt)
$hwnd = [WinDetect]::WindowFromPoint($pt)
# 获取最外层窗口
$root = [WinDetect]::GetAncestor($hwnd, 2)
if ($root -ne [IntPtr]::Zero) {
$hwnd = $root
}
$procId = [uint32]0
[void][WinDetect]::GetWindowThreadProcessId($hwnd, [ref]$procId)
$title = New-Object System.Text.StringBuilder 512
$class = New-Object System.Text.StringBuilder 512
[void][WinDetect]::GetWindowText($hwnd, $title, 512)
[void][WinDetect]::GetClassName($hwnd, $class, 512)
$proc = Get-CimInstance Win32_Process -Filter "ProcessId=$procId"
Write-Host ""
Write-Host "HWND :" $hwnd
Write-Host "窗口标题 :" $title.ToString()
Write-Host "窗口类名 :" $class.ToString()
Write-Host "PID :" $procId
Write-Host "进程名 :" $proc.Name
Write-Host "程序路径 :" $proc.ExecutablePath
Write-Host "命令行 :" $proc.CommandLine
Write-Host "父进程 PID :" $proc.ParentProcessId真凶出现了:Telegram#
执行脚本之后,最关键的输出是:
窗口标题 :
窗口类名 : MicrosoftWindowsTooltip
进程名 : Telegram.exe
程序路径 : C:\Users\<用户名>\AppData\Roaming\Telegram Desktop\Telegram.exe
命令行 : "C:\Users\<用户名>\AppData\Roaming\Telegram Desktop\Telegram.exe" -noupdate这里已经几乎可以直接确定:
这个烦人的 “Close” 是 Telegram Desktop 创建出来的。
为了进一步验证,我直接退出了 Telegram。
结果——
那个悬浮在屏幕最前面的 “Close” 立刻消失。
至此,问题彻底确认。
原来它不是普通窗口,而是 Tooltip#
更有意思的是这一行:
窗口类名 : MicrosoftWindowsTooltip也就是说,这个东西本质上并不是 Telegram 的一个正常窗口,而是一个 Windows Tooltip(工具提示)。
正常情况下,它可能只是 Telegram 某个按钮在鼠标悬停时短暂显示的 “Close”。
但不知道因为什么原因——可能是界面刷新、窗口状态切换、休眠唤醒,或者单纯就是 Telegram Desktop 的 UI Bug——这个 Tooltip 没有被正常销毁,于是留在了桌面上。
这也解释了它之前那些诡异的行为:
- 不能拖动,因为 Tooltip 本来就不是普通窗口;
- 不能正常右键操作,因为它不是为交互设计的;
- 一直保持置顶,因为 Tooltip 往往使用顶层窗口;
Win + D对它没有正常效果;- 切换虚拟桌面后,它仍然可能继续存在;
- Telegram 退出后,所属进程结束,Windows 自动销毁对应窗口,于是它立即消失。
解决方案,简要版#
如果以后再遇到类似的“幽灵窗口”,可以按照下面的方法排查:
先观察异常窗口的行为。
比如它是否始终置顶、是否能拖动、Win + D是否有效、切换虚拟桌面后是否仍然存在。把鼠标移动到异常窗口上。
运行上面的 PowerShell 脚本。
它会通过WindowFromPoint获取鼠标所在位置的窗口,再通过GetWindowThreadProcessId找到创建这个窗口的进程。重点查看:
- 窗口类名
- 进程名
- 程序路径
- 命令行
- 父进程 PID
退出对应软件进行验证。
如果异常窗口随着软件退出立即消失,那么基本就可以确认来源。
这套方法最大的好处是:
不需要靠猜,也不需要一个一个关闭程序。
Windows 自己其实知道屏幕上的窗口属于谁,我们只是通过 Win32 API 把这个信息查了出来。
这次我也想夸夸自己#
既然文章标题叫《谢谢你,ChatGPT》,当然要夸 ChatGPT。
但 ChatGPT 在最后也指出,这次排查能够这么顺利,我自己的提问方式其实也发挥了很大作用。
我觉得下面几点确实值得保留:
第一,我描述了可验证的现象。
我没有只说“桌面上出现了一个奇怪的 Close”,而是补充说明:
Win + D 无法隐藏、任何窗口都盖不住、虚拟桌面之间也存在。
这些细节对判断窗口类型非常重要。
第二,我愿意执行一个可验证的诊断步骤。
拿到 PowerShell 脚本之后,我没有停留在猜测阶段,而是直接运行它,让系统告诉我这个窗口到底属于哪个 PID 和哪个 EXE。
第三,我把完整结果反馈了回来。
我没有只回复一句“好像是 Telegram”,而是把窗口类名、PID、进程名、程序路径、命令行和父进程 PID 都贴了出来。
这样 ChatGPT 才能进一步发现:
MicrosoftWindowsTooltip这个非常关键的线索。
第四,我又做了一次因果验证。
查到 Telegram.exe 之后,我直接退出 Telegram。
Close 当场消失。
这一步很重要,因为它把“相关”变成了“基本可以确认的因果关系”。
从这个角度看,这其实是一套非常标准的故障排查过程:
观察现象 → 提出假设 → 获取系统信息 → 锁定对象 → 实验验证。
谢谢你,ChatGPT#
这件事本身不算什么大问题。
它不会导致电脑无法启动,也没有造成数据丢失。
但这种小问题最容易让人难受:
屏幕上就那么挂着一个东西,你看得见它,却不知道它是什么;你没法拖走它,也不知道是谁创建了它。
过去遇到这种情况,我可能会选择:
关几个软件试试,不行就重启电脑。
重启当然大概率也能解决。
但那样我永远不会知道:
它究竟是谁留下来的?
这一次,ChatGPT 没有让我重启电脑,也没有让我盲目卸载软件,而是给了我一小段 PowerShell,让我直接问 Windows:
“鼠标现在指着的这个窗口,到底属于哪个进程?”
几秒钟后,Windows 给出了答案:
Telegram.exe问题解决了,而且我还顺便学到了 WindowFromPoint、窗口句柄、PID,以及 MicrosoftWindowsTooltip 这些原本完全不会去了解的东西。
所以,这篇文章就叫: