Total Commander 主线程卡死问题排查

Total Commander 主线程卡死问题排查

问题现象

某天正愉快地用 Total Commander(64位)管理文件,右键一点……好家伙,整个界面直接石化,鼠标转圈圈,窗口标题栏写着大大的"未响应"。只能含泪打开任务管理器把它送走。

用 PowerShell 确认一下,果然凉了:

Get-Process -Name "TOTALCMD64" | Select-Object Id, ProcessName, Responding

输出:

   Id ProcessName Responding
   -- ----------- ----------
 1234 TOTALCMD64       False

Responding = False,实锤了——主线程消息循环彻底罢工。


排查工具

工具干啥用的
PowerShell确认进程状态、生成 dump 文件
WinDbg打开 dump 文件,翻线程调用栈找"凶手"
dbghelp.dll提供 MiniDumpWriteDump API,用来给进程"拍快照"

排查步骤

第一步:给卡死的进程拍个"遗照"(生成 Dump)

进程卡死了但没崩,系统不会自动生成 dump,得我们自己动手。

写个 PowerShell 脚本 dump.ps1

Add-Type -TypeDefinition @"
using System;
using System.Runtime.InteropServices;
public class MiniDumpHelper {
    [DllImport("dbghelp.dll", SetLastError = true)]
    public static extern bool MiniDumpWriteDump(
        IntPtr hProcess, uint processId, IntPtr hFile, 
        uint dumpType, IntPtr exceptionParam, 
        IntPtr userStreamParam, IntPtr callbackParam);
}
"@

$processId = <目标进程PID>
$process = Get-Process -Id $processId
$dumpPath = "D:\temp\totalcmd64.dmp"
$fileStream = New-Object System.IO.FileStream($dumpPath, [System.IO.FileMode]::Create)
# dumpType=2 表示 MiniDumpWithFullMemory(完整内存快照)
$result = [MiniDumpHelper]::MiniDumpWriteDump(
    $process.Handle, $processId, 
    $fileStream.SafeFileHandle.DangerousGetHandle(), 
    2, [IntPtr]::Zero, [IntPtr]::Zero, [IntPtr]::Zero)
$fileStream.Close()
Write-Host "Dump created: $result"

跑起来:

powershell -ExecutionPolicy Bypass -File dump.ps1

看到 Dump created: True,快照到手。


第二步:请出 WinDbg 大夫,加载 Dump

.sympath srv*C:\Symbols*https://msdl.microsoft.com/download/symbols
.open D:\temp\totalcmd64.dmp
.reload

符号服务器配好,微软的 DLL 就都能解析出函数名了。


第三步:看看这是啥类型的 Dump

.exr -1

输出:

ExceptionAddress: 0000000000000000
   ExceptionCode: 80000003 (Break instruction exception)
  ExceptionFlags: 00000000
NumberParameters: 0

80000003 是断点异常——说明这是我们手动抓的快照,不是崩溃。分析方向:挂起/死锁


第四步:翻主线程的调用栈(破案关键)

切到主线程,看看它到底卡在哪儿:

~0s
k

调用栈(精简版,从上到下是从"表象"到"根源"):

ntdll!NtWaitForSingleObject+0x14           ← 卡在这儿:死等一个内核对象
KERNELBASE!WaitForSingleObjectEx+0x8e
SHCore!SHCreateThread+0x143
windows_storage!DataAccessCaches_InvalidateForLibrary+0x274a
...
shell32!SHELL32_IconCache_AboutToExtractIcons+0x1df
user32!DispatchMessageW+0x741
user32!CreateWindowExW+0x82
YunShellExtV164+0xd8232                    ← ★ 就是你!百度网盘Shell扩展
YunShellExtV164+0x1106c8
YunShellExtV164!DllGetClassObject+0x69     ← ★ 初始化COM对象时出的事
YunShellExtV164!DllUnregisterServer+0x57bc
ntdll!LdrLoadDll+0xfa
KERNELBASE!LoadLibraryExW+0x172
combase!CoCreateInstance+0x14c             ← 系统在创建COM实例
shell32!SHELL32_SHCreateDefaultContextMenu ← 系统在构建右键菜单
TOTALCMD64+0x20013e                        ← TC说:我就想弹个右键菜单啊!

一眼看出来了:百度网盘的 Shell 扩展在初始化时卡住了,连累整个主线程一起躺平。


第五步:确认"凶手"身份

lm m YunShellExtV164

输出:

start             end                 module name
00007ffc`5db60000 00007ffc`5ddf7000   YunShellExtV164   (export symbols)  YunShellExtV164.dll

YunShellExtV164 = “云”(Yun) + ShellExt + V1 + 64位 → 百度网盘的右键菜单扩展,破案了。


根因分析

调用链还原

TC: 我想弹个右键菜单

shell32: 好嘞,让我加载所有扩展

COM: 来,加载百度网盘扩展

百度网盘: 等我初始化一下...

百度网盘: 我要创建个窗口

windows_storage: 帮我枚举一下存储信息

SHCore: 开个线程干活,你等着

主线程: 等...等...等到天荒地老 ☠️

来龙去脉

  1. Total Commander 在主线程上同步调用 SHCreateDefaultContextMenu 想弹个右键菜单
  2. 系统乖乖地逐个加载所有注册的右键扩展,轮到了百度网盘的 YunShellExtV164.dll
  3. 这哥们在初始化时搞了一堆骚操作:创建窗口、枚举存储信息……
  4. 最后开了个工作线程,然后主线程傻等这个线程干完活
  5. 然而那个线程似乎永远也干不完 → 主线程:???我等到花儿都谢了

解决方案

方案一:打开百度网盘设置,禁用 Shell 扩展(推荐)

第一步:打开百度网盘 → 点击右上角菜单按钮 → 选择「设置」
在这里插入图片描述

第二步:取消勾选"在我的电脑显示网盘"
在这里插入图片描述

第三步:在任务管理器中杀掉 Total Commander 进程,重新启动即可恢复正常。

方案二:卸载百度网盘

简单粗暴,一了百了。如果你平时不怎么用百度网盘桌面端,直接卸了清净。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值