在 CFAPI 的学习过程中,大多数人会很快接触到CF_CALLBACK_TYPE_FETCH_DATA → OnFetchData,
却长期搞不清一个核心问题:
OnFetchData 到底是谁执行的?
答案并不在你的代码里,而在一个被 CFAPI 隐藏起来的执行入口:
CfExecute
一、先给结论(重要)
CFAPI 并不是“事件回调模型”,而是“系统驱动执行模型”。
你只负责:
注册 SyncRoot
注册 Callback
真正执行 Cloud Files 逻辑的入口是 CfExecute
OnFetchData 只是 CfExecute 分发出来的一个执行分支
二、CFAPI 的真实执行链路
文件访问到 OnFetchData 的完整路径
用户 / 应用访问文件 ↓ I/O Manager ↓ NTFS + Filter Manager ↓ cldflt.sys(Cloud Files Filter) ↓ CFAPI Runtime ↓ CfExecute ←【执行入口】 ↓ CF_CALLBACK_TYPE_FETCH_DATA ↓ OnFetchData关键点:
❌ OnFetchData不是你主动调用
❌ 也不是 CreateFile 直接调用
✅是 CfExecute 在执行 Cloud Files 语义时分发
三、CfExecute 是什么?为什么你看不到?
1. CfExecute 的角色
CfExecute 是 CFAPI 内部的“执行调度器”,负责:
判定当前文件操作是否属于 Cloud Files
选择合适的 Callback 类型
调度并发与线程
驱动整个占位符生命周期
2. 为什么 API 中没有 CfExecute?
因为:
它不属于 Provider 可控范围
由系统在内核 / Runtime 层自动调用
目的是保证文件系统一致性
你只需要通过:
CfConnectSyncRoot(...)把自己“挂”到 CfExecute 上。
四、CfConnectSyncRoot 做了什么(本质)
CfConnectSyncRoot( SyncRootPath, CallbackMappings, ProviderContext, Flags, out ConnectionKey );这一步的本质是:
告诉 CFAPI Runtime:
“这个路径下的 Cloud Files 由我负责”
“当 CfExecute 执行到这里时,用这些 Callback”
没有这一步:
CfExecute 不会路由到你
OnFetchData 永远不会被调用
五、OnFetchData 什么时候会被 CfExecute 分发?
触发条件(同时满足)
文件是占位符(Placeholder)
文件当前状态需要内容数据
当前操作触及文件内容
满足后:
CfExecute → CF_CALLBACK_TYPE_FETCH_DATA → OnFetchData常见触发行为
| 行为 | 是否触发 |
|---|---|
| ReadFile | ✅ |
| Copy 文件 | ✅ |
| Explorer 打开 | ✅ |
| 只读取属性 | ❌ |
| FILE_FLAG_OPEN_REPARSE_POINT | ❌ |
| 完整 Hydrated 文件 | ❌ |
六、为什么“CreateFile 看起来触发了 OnFetchData”?
这是你之前反复遇到的问题,本质原因在 CfExecute。
原因拆解
CreateFile本身 ≠ Fetch但:
Explorer 会在 CreateFile 后做探测性 Read
某些 Flag 会触发缓冲读取
CfExecute 判断:需要内容数据
→ 分发 FetchData
所以现象是:
你以为是 CreateFile 触发,实际上是后续的隐式 Read 触发
七、OnFetchData 的执行语义(非常关键)
OnFetchData 并不等于“下载文件”
它的真实语义是:
“请提供 [Offset, Offset + Length) 这段数据”
因此:
Fetch 可能:
多次
不连续
并发
Offset 可能不是 0
Length 不等于文件大小
八、OnFetchData 的标准处理闭环
正确的执行顺序
OnFetchData 被 CfExecute 分发 ↓ 解析 Offset / Length ↓ 从云端或缓存读取对应数据 ↓ CfWriteFile 写入指定 Offset ↓ CfCompleteFetchData(HRESULT.S_OK)如果漏掉最后一步?
CfExecute 认为请求未完成
文件访问卡死
Explorer 无响应
九、CfExecute 下的并发与线程模型
你必须接受的事实
CfExecute:
多线程
并发
可重入
同一文件:
可能多个 Fetch 同时发生
Provider 的要求
OnFetchData:
必须线程安全
不要长时间阻塞
支持 Range 下载
十、统一理解(工程师视角)
CfExecute 是 CFAPI 的“隐形主循环”,
OnFetchData 是它在执行“文件内容请求”时分发出来的一个回调。
你不是在“监听事件”,
而是在参与 Windows 文件系统的一次执行流程。
十一、一句话总结
CfExecute 决定“什么时候执行”
OnFetchData 决定“如何给数据”
Provider 只是被动参与系统执行
只要你用这个模型去理解 CFAPI,
你前面遇到的Fetch 乱触发、句柄问题、卡死问题,都会自然对上。