应选择Dokan 2.x + DokanNet 2.x(如2.4.0+),因DokanNet 1.x已废弃且不兼容新版Windows;需管理员权限安装对应平台的Dokan驱动,挂载前检查盘符占用与路径合法性,并严格遵循IRP生命周期实现IDokanOperations回调。

DokanNet 和 Dokan 2.x 的选择问题
现在用 C# 做 Windows 虚拟文件系统,DokanNet 已基本废弃,官方推荐迁移到 Dokan 2.x + DokanNet 2.x(即基于 .NET Standard 2.0 的新绑定)。老项目如果还在用 DokanNet 1.x,启动时大概率报 System.DllNotFoundException: dokan1.dll 或挂载后立即断连——因为新版 Windows(尤其是 22H2+)不再兼容旧版 dokan1.dll 的驱动模型。
实操建议:
- 新项目直接用
DokanNet 2.4.0+(NuGet 包名:DokanNet),它依赖Dokan 2.0.0+驱动,需单独安装DokanSetup.exe - 必须在目标机器上运行
DokanSetup.exe安装驱动,仅引用 NuGet 包不生效;未安装时Dokan.Mount()会静默失败或抛DokanOperationException - 注意平台目标:x64 应用只能挂载 x64 驱动,x86 应用需装 x86 版 Dokan 驱动(但 Win10/11 默认只提供 x64 安装包)
Mount() 失败但没报错的常见原因
Dokan.Mount() 返回 false 或直接退出,控制台无异常、事件日志也空,这是最典型的“挂载静默失败”。根本原因往往不是代码逻辑,而是权限或路径冲突。
实操建议:
- 必须以管理员权限运行程序,否则
IRP_MJ_CREATE在驱动层被拦截,Mount()直接返回 false - 检查盘符是否已被占用(包括隐藏的卷、网络映射、BitLocker 保护卷),
Dokan.Mount("Z:", ...)中的盘符不能是Z:且当前已存在Z:目录 - 避免使用
C:、D:等物理盘符;也不要用\?Volume{...}这类 NT 对象路径作为挂载点 - 调试时加
new DokanOptions { DebugMode = true, StdErr = true },错误会输出到控制台 stderr
实现 IDokanOperations 时最容易崩的三个地方
继承 IDokanOperations 后,CreateFile、ReadFile、FindFiles 这三个方法写错,会导致资源管理器卡死、蓝屏(BSOD)或 Dokan 驱动自动卸载。不是语法错,而是语义和生命周期违规。
实操建议:
-
CreateFile必须返回NTSTATUS.STATUS_SUCCESS或明确的错误码(如STATUS_OBJECT_NAME_NOT_FOUND),绝不能抛托管异常;C# 异常无法跨驱动边界传递,会触发DRIVER_IRQL_NOT_LESS_OR_EQUAL -
ReadFile的buffer是非托管内存,必须用Marshal.Copy()写入,不能直接赋值数组或用Span<byte>.CopyTo()</byte>(可能越界) -
FindFiles中调用FillFindData时,fileName必须是合法的 DOS 文件名(不含/、、:、?等),且长度 ≤ 255 字符;传入".."或"."会引发 Explorer 崩溃
调试 Dokan 驱动行为的最低成本方式
靠 Console.WriteLine 或 VS Debugger 几乎无效:Dokan 驱动运行在内核态,用户态回调被异步调度,断点会卡死整个系统;日志打太快还会触发 Dokan 的 rate-limit 机制,后续请求直接丢弃。
实操建议:
- 用
DbgView(Sysinternals 工具)捕获DbgPrint级别日志,DokanNet 2.x 默认开启,关键路径会输出类似[DokanNet] CreateFile: est.txt - 在
CreateFile开头加if (fileName == ".") return NtStatus.StatusObjectPathNotFound;,快速排除根目录枚举导致的无限递归 - 挂载后立刻在 PowerShell 执行
Get-PSDrive Z,若返回空说明挂载失败;执行dir Z:报The network path was not found通常是驱动未加载或权限不足
真正难的不是写通一个 FindFiles,而是让每个回调都满足 IRP 生命周期约束——比如 CloseFile 可能永远不来,Cleanup 却先到了,这时候释放资源的顺序和判断条件,文档里几乎不提,全靠看 DokanNet 源码里的 sample 实现反推。











