症状:Ctrl+C / Ctrl+V 全部失效,重启能好一阵,过段时间又犯。
结果:揪出一个开机自启、不干任何活、却死死占着剪贴板的"僵尸进程"。
用时:约 40 分钟(其中一半时间花在排除嫌疑上)。


一、先说结论

问题不在键盘、不在微信、不在输入法,而是一个 32 位的僵尸 svchost.exe 进程(PID 34108)长期调用 OpenClipboard() 却不释放,导致系统里其他所有程序的剪贴板操作一律返回 错误码 5(Access Denied)。

终止它之后,剪贴板瞬间恢复。

而它之所以每次重启后"好一阵又坏",是因为它随系统启动重新生成,然后再次把剪贴板锁死。


二、第一反应:重启能好,那就不重启地"重启"

以前每次犯病我都直接重启电脑,确实能好。但这次我想省事,于是按经验从轻到重试:

操作命令结果
清空剪贴板缓冲Set-Clipboard -Value $null❌ 直接报"剪贴板操作失败"
重启资源管理器Stop-Process -Name explorer -Force❌ 无效
重启剪贴板服务Restart-Service cbdhsvc_bfb46 -Force❌ 无效

注意第一条:连清空剪贴板都报错,这已经是很强的信号——不是某个软件"复制不进去",而是整个剪贴板根本无法被打开。

三、第二步:逐个排除嫌疑软件,全部排除

剪贴板是 Windows 里最容易被"监听"的资源,各类 IM、办公软件、输入法、云盘都会注册监听。于是一路关下去:

  • 微信、QQ、飞书、WPS、QQ音乐 → 关掉,无效
  • 搜狗输入法助手、腾讯文档、豆包、企业微信 → 关掉,无效
  • Chrome、Trae、闲管家、WeMail、OneDrive、clash-verge → 关掉,无效
  • 火绒安全 → 手动退出,无效

到这里可以确定:不是某个应用的问题。继续关软件没有意义,必须换个思路——从"猜"转向"测"。

四、关键判断:区分键盘问题还是剪贴板问题

两个小测试直接分离了故障层:

  1. 用鼠标右键菜单复制/粘贴(不碰键盘)→ 同样失效 ⇒ 排除键盘、Ctrl 键、输入法拦截。
  2. 按 Win+V 呼出剪贴板历史面板 → 面板能正常弹出,但点历史记录粘贴没反应 ⇒ 剪贴板服务进程活着,但数据传输通道被堵死。

结论锁定:问题在系统剪贴板本身,不在上层应用。

五、转折点:让系统自己告诉我们"是谁占着"

Windows 有一个几乎没人用的 API:

HWND GetOpenClipboardWindow(void);

它返回当前正持有剪贴板打开的窗口句柄。如果剪贴板被某个进程 OpenClipboard() 后没有 CloseClipboard(),这里就会返回那个窗口。

拿到句柄后,再两步就能定位到进程:

GetWindowThreadProcessId(hwnd, &pid);   // 句柄 → 进程 ID
QueryFullProcessImageNameW(...);        // 进程 ID → 可执行文件路径

问题是 PowerShell 里用 Add-Type 编译 C# 调用这些 API,在某些受限环境下会被安全策略拦截。于是改用 Python + ctypes,直接调 Win32 API,一行编译都不用:

import ctypes
from ctypes import wintypes

user32 = ctypes.WinDLL('user32', use_last_error=True)
user32.GetOpenClipboardWindow.restype = wintypes.HWND
user32.GetWindowThreadProcessId.argtypes = [wintypes.HWND, ctypes.POINTER(wintypes.DWORD)]
user32.OpenClipboard.argtypes = [wintypes.HWND]
user32.OpenClipboard.restype = wintypes.BOOL
user32.CloseClipboard.restype = wintypes.BOOL

# 1) 谁把剪贴板"打开着"没关?
h = user32.GetOpenClipboardWindow()
pid = wintypes.DWORD()
user32.GetWindowThreadProcessId(h, ctypes.byref(pid))
print("占用者 PID:", pid.value)

# 2) 我们还能不能打开剪贴板?
ok = 0
for i in range(5):
    if user32.OpenClipboard(None):
        ok += 1
        user32.CloseClipboard()
    else:
        print("第 %d 次失败,错误码 %d" % (i + 1, ctypes.get_last_error()))
        break
print("可打开次数:", ok, "/ 5")

输出(真实结果):

[1] 当前持有剪贴板打开的窗口: 134360
    >>> 锁定进程: svchost.exe  PID: 34108
    路径: C:\Windows\SysWOW64\svchost.exe
    窗口类名: Static

[3] 尝试打开剪贴板 5 次...
    第 1 次失败, 错误码 5
    可打开次数: 0 / 5

六、确认这个 svchost 是不是"正常"的

svchost.exe 是服务宿主进程,一个正常实例必然承载着具体服务。所以关键三问:

# 1) 它承载了什么服务?(tasklist 的 /svc 参数)
tasklist /svc /fi "PID eq 34108" /fo list
# 输出:服务: 暂缺          ← 一个服务都没有

# 2) 文件本身是正版吗?
Get-AuthenticodeSignature 'C:\Windows\SysWOW64\svchost.exe'
# 输出:Valid / CN=Microsoft Windows

# 3) 命令行正常吗?
Get-CimInstance Win32_Process -Filter "ProcessId=34108" | Select CommandLine
# 输出:svchost.exe -k LocalService 201 200   ← 非标准格式,正常应为 -k LocalServiceNetworkRestricted 之类

三条结论:

  • ✅ 文件是微软正版,不是病毒伪装
  • ❌ 不承载任何服务 —— 标准的"僵尸服务宿主"
  • ❌ 父进程已消失(PID 15544 查不到)
  • ⚠️ 启动时间为开机后 1 分半,说明它随系统启动产生

七、动手:杀了它,秒好

Stop-Process -Id 34108 -Force

重新跑诊断脚本:

[1] 当前持有剪贴板打开的窗口: 无 (None)
[3] 尝试打开剪贴板 5 次... 可打开次数: 5 / 5

再往剪贴板写一段测试文本、按 Ctrl+V,粘贴正常。40 分钟的排查,1 秒钟解决。

八、防止复发:装一个"剪贴板看门狗"

杀进程只解决当下,重启后僵尸会重新出现。既然它的特征很明确(是 svchost 但不承载任何服务),就可以写个静默看门狗,每 5 分钟巡检一次:

# 核心逻辑(简化版)
if can_open_clipboard():        # 一切正常,直接退出,零开销
    return

h = GetOpenClipboardWindow()    # 找出占用者
pid, name, svc = resolve(h)

if name.lower() == "svchost.exe" and svc in ("", "暂缺", "N/A"):
    taskkill(pid)               # 僵尸 svchost → 直接干掉
restart_service("cbdhsvc*")     # 顺手重启剪贴板服务

注册成计划任务,登录时 + 每 5 分钟运行一次,最高权限、隐藏窗口:

$action  = New-ScheduledTaskAction -Execute 'C:\Program Files\python\pythonw.exe' `
           -Argument '"C:\Users\你\AppData\Local\ClipGuard\clip_watch.py"'
$trigger = New-ScheduledTaskTrigger -AtLogOn
$repeat  = New-ScheduledTaskTrigger -Once -At (Get-Date) `
           -RepetitionInterval (New-TimeSpan -Minutes 5) `
           -RepetitionDuration (New-TimeSpan -Days 3650)
$principal = New-ScheduledTaskPrincipal -UserId "$env:USERDOMAIN\$env:USERNAME" `
             -RunLevel Highest -LogonType Interactive

Register-ScheduledTask -TaskName 'ClipGuard-Watchdog' -Action $action `
  -Trigger @($trigger, $repeat) -Principal $principal -Force

从此以后,剪贴板再被锁,5 分钟内会被自动修好,而且日志会记下"是谁干的"。

九、这次排查学到的几件事

1. 报错信息比症状更有价值。
"剪贴板操作失败"只是一句话;但 OpenClipboard 返回的错误码 5(Access Denied)直接指出:有别人正占着,而不是权限或配置问题。

2. 分层定位,别在应用层瞎转。
关掉 15 个软件都不管用时,说明该往下一层走了。右键复制 + Win+V 两个测试,10 秒就把问题从"应用层"砍到"系统层"。

3. svchost.exe 不是黑盒,它必须"有活干"。
一个不承载任何服务的 svchost,加上不标准的命令行、消散的父进程、开机即启动——这几个特征凑在一起,基本可以判定为僵尸进程。杀之无害(它没在服务任何东西)。

4. Windows 自带 API 里藏着很多"体检工具"。
GetOpenClipboardWindow、GetClipboardOwner、GetClipboardViewer 这三个函数,分别能回答"谁占着"、"内容属于谁"、"谁在监听"。遇到剪贴板类问题,先问这三个问题,比关 15 个软件快得多。

5. 我还欠系统一个更新。
排查中发现这台机器最后一次装补丁是15 个月前。这类服务残留 bug 很可能在新版累积更新里已经修掉了。修 bug 的同时,也别忘了修系统。


附:可以直接用的排查模板

如果你也遇到剪贴板失灵,按这个顺序走,基本 5 分钟能定性:

# 1. 是不是剪贴板本身坏了?(能打开就说明没被锁)
powershell -c "Set-Clipboard 'test'; Get-Clipboard"

# 2. 谁占着?(用上面的 Python 脚本,或 Sysinternals Handle)
#    重点看 GetOpenClipboardWindow 返回的 PID

# 3. 那个进程正常吗?
tasklist /svc /fi "PID eq <PID>" /fo list     # 服务是否为"暂缺"
Get-CimInstance Win32_Process -Filter "ProcessId=<PID>" | Select CommandLine

# 4. 确认是僵尸 → 结束它 → 立即验证
Stop-Process -Id <PID> -Force

顺手也检查一下剪贴板监听链——很多人不知道,一堆软件在后台盯着你复制了什么:

user32.GetClipboardViewer()          # 链表头
user32.GetClipboardViewerNext(hwnd)  # 顺着链表走一遍

我的机器上就有 SogouCloud.exe(类名 ImeGuard)挂在里面。它本身不等于故障,但如果剪贴板频繁出问题,这类常驻监听者值得优先怀疑。


写于一次差点又要重启电脑的夜晚。

最后修改:2026 年 11 月 04 日
如果觉得我的文章对你有用,请随意赞赏