cfapi CF_CALLBACK_TYPE_FETCH_PLACEHOLDERS 重复回调

leg*_*mbo 3 c++ windows winapi minifilter

我正在使用 cfapi 并尝试扩展此处提供的示例项目https://github.com/Microsoft/Windows-classic-samples/tree/master/Samples/CloudMirror

具体来说,我们希望实现 CF_CALLBACK_TYPE_FETCH_PLACEHOLDERS 以按需提供目录内容。我们的回调是这样注册的:-

CF_CALLBACK_REGISTRATION FakeCloudProvider::s_MirrorCallbackTable[] =
{
    { CF_CALLBACK_TYPE_FETCH_PLACEHOLDERS, FakeCloudProvider::OnFetchPlaceholders },
    { CF_CALLBACK_TYPE_FETCH_DATA, FakeCloudProvider::OnFetchData },
    { CF_CALLBACK_TYPE_CANCEL_FETCH_DATA, FakeCloudProvider::OnCancelFetchData },
    CF_CALLBACK_REGISTRATION_END
};
Run Code Online (Sandbox Code Playgroud)

OnFetchPlaceholders 方法调用 CfExecute() 以使用服务器目录中关联文件的占位符数组来响应回调。

CF_OPERATION_INFO opInfo = { 0 };
CF_OPERATION_PARAMETERS opParams = { 0 };

opInfo.StructSize = sizeof(opInfo);
opInfo.Type = CF_OPERATION_TYPE_TRANSFER_PLACEHOLDERS;
opInfo.ConnectionKey = callbackInfo->ConnectionKey;
opInfo.TransferKey = callbackInfo->TransferKey;

opParams.ParamSize = sizeof(opParams);
opParams.TransferPlaceholders.CompletionStatus = status;
opParams.TransferPlaceholders.Flags = CF_OPERATION_TRANSFER_PLACEHOLDERS_FLAG_NONE;
opParams.TransferPlaceholders.PlaceholderArray = placeholders;
opParams.TransferPlaceholders.PlaceholderCount = placeholdersCount;
opParams.TransferPlaceholders.PlaceholderTotalCount.QuadPart = placeholdersCount;

winrt::check_hresult(CfExecute(&opInfo, &opParams));
Run Code Online (Sandbox Code Playgroud)

出乎意料的是,由于服务器目录中只有三个文件且没有子目录,OnFetchPlacehodlers 函数会被快速连续调用多次(在我刚刚进行的测试中为 457 次),以至于 Explorer 停止响应一段时间。奇怪的是,该方法被调用的次数似乎在 200 到 500 次之间变化,但似乎没有任何可辨别的模式。

我尝试CF_OPERATION_TRANSFER_PLACEHOLDERS_FLAG_DISABLE_ON_DEMAND_POPULATION在回调中设置标志,当我这样做时,我们只被调用一次,但一旦设置,即使我们有新的占位符要提供,我们也不会再被要求提供占位符。

小智 5

我相信文件夹只需要在第一次访问期间填充一次,然后您将需要使用其他方法来使其内容同步(例如定期拉取服务器)。

根据我使用 API 的经验,如果您不禁用按需填充,则 explorer.exeSearchProtocolHost.exe Windows 索引服务)对该文件夹的每次访问都会触发一个新的FetchPlaceholders回调,我认为这是之所以会重复触发回调,这不仅会影响系统性能,还会增加服务器的负载。

如果您确实需要“撤销” CF_OPERATION_TRANSFER_PLACEHOLDERS_FLAG_DISABLE_ON_DEMAND_POPULATION ,只需调用CfUpdatePlacehoder API 并传入CF_UPDATE_FLAG_ENABLE_ON_DEMAND_POPULATION标志,这将重新启用按需填充,并且将来对此文件夹的任何访问都将再次触发 FETCH_PLACEHOLDERS 回调。