Total Commander 主线程卡死问题排查
Total Commander 主线程卡死问题排查——百度网盘 Shell 扩展:你搁这等啥呢?
- Total Commander 主线程卡死问题排查
- 问题现象
- 排查工具
- 排查步骤
- 第一步:给卡死的进程拍个"遗照"(生成 Dump)
- 第二步:请出 WinDbg 大夫,加载 Dump
- 第三步:看看这是啥类型的 Dump
- 第四步:翻主线程的调用栈(破案关键)
- 第五步:确认"凶手"身份
- 根因分析
- 调用链还原
- 来龙去脉
- 解决方案
- 方案一:打开百度网盘设置,禁用 Shell 扩展(推荐)
- 方案二:卸载百度网盘
Total Commander 主线程卡死问题排查
问题现象
某天正愉快地用 Total Commander(64位)管理文件,右键一点……好家伙,整个界面直接石化,鼠标转圈圈,窗口标题栏写着大大的"未响应"。只能含泪打开任务管理器把它送走。
用 PowerShell 确认一下,果然凉了:
Get-Process-Name"TOTALCMD64"|Select-ObjectId,ProcessName,Responding输出:
Id ProcessName Responding -- ----------- ---------- 1234 TOTALCMD64 FalseResponding = False,实锤了——主线程消息循环彻底罢工。
排查工具
| 工具 | 干啥用的 |
|---|---|
| PowerShell | 确认进程状态、生成 dump 文件 |
| WinDbg | 打开 dump 文件,翻线程调用栈找"凶手" |
| dbghelp.dll | 提供MiniDumpWriteDumpAPI,用来给进程"拍快照" |
排查步骤
第一步:给卡死的进程拍个"遗照"(生成 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-ObjectSystem.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: 080000003是断点异常——说明这是我们手动抓的快照,不是崩溃。分析方向:挂起/死锁。
第四步:翻主线程的调用栈(破案关键)
切到主线程,看看它到底卡在哪儿:
~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.dllYunShellExtV164=“云”(Yun) + ShellExt + V1 + 64位→ 百度网盘的右键菜单扩展,破案了。
根因分析
调用链还原
来龙去脉
- Total Commander 在主线程上同步调用
SHCreateDefaultContextMenu想弹个右键菜单 - 系统乖乖地逐个加载所有注册的右键扩展,轮到了百度网盘的
YunShellExtV164.dll - 这哥们在初始化时搞了一堆骚操作:创建窗口、枚举存储信息……
- 最后开了个工作线程,然后主线程傻等这个线程干完活
- 然而那个线程似乎永远也干不完 → 主线程:???我等到花儿都谢了
解决方案
方案一:打开百度网盘设置,禁用 Shell 扩展(推荐)
第一步:打开百度网盘 → 点击右上角菜单按钮 → 选择「设置」
第二步:取消勾选"在我的电脑显示网盘"
第三步:在任务管理器中杀掉 Total Commander 进程,重新启动即可恢复正常。
方案二:卸载百度网盘
简单粗暴,一了百了。如果你平时不怎么用百度网盘桌面端,直接卸了清净。