Windows10文件云/同步提供程序API-TransferData问题

我在建设云镜样品和具有类似问题这一个

下面是所涉及的测试代码:

        // When the client needs to fetch data from the cloud, this method will be called.
    // The FakeMirrorDataMover class does the actual work of copying files from
    // the "cloud" to the "client" and updating the transfer status along the way.
    void CALLBACK FakeCloudProvider::OnFetchData(
        _In_ CONST CF_CALLBACK_INFO* callbackInfo,
        _In_ CONST CF_CALLBACK_PARAMETERS* callbackParameters)
    {
        //FileCopierWithProgress::CopyFromServerToClient(callbackInfo, callbackParameters, ProviderFolderLocations::GetServerFolder());
    
            const UINT CHUNKSIZE = 48 * 1024 * 1024;
            UINT len;
            LONG64 offset = callbackParameters->FetchData.RequiredFileOffset.QuadPart;
            LONG64 requiredLength = callbackParameters->FetchData.RequiredLength.QuadPart;
            byte *buffer = new byte[CHUNKSIZE];
            FillMemory(buffer, CHUNKSIZE, (byte)0xA5);
    
            while (0 < requiredLength)
            {
                len = requiredLength < CHUNKSIZE ? requiredLength : CHUNKSIZE;
                if (0 != len % 4096)
                    len = 4096 * (len / 4096 + 1);
    
                Placeholders::TransferData(callbackInfo->TransferKey.QuadPart, buffer, offset, len, 0);
    
                requiredLength -= len;
                offset += len;
            }
    
            delete[] buffer;
    }

HRESULT Placeholders::TransferData(
    //_In_ CF_CONNECTION_KEY connectionKey,
    _In_ LONG64 transferKey,
    _In_reads_bytes_opt_(length.QuadPart) LPCVOID transferData,
    _In_ LONG64 startingOffset,
    _In_ LONG64 length,
    _In_ NTSTATUS completionStatus)
{
    CF_OPERATION_INFO opInfo = { 0 };
    CF_OPERATION_PARAMETERS opParams = { 0 };

    opInfo.StructSize = sizeof(opInfo);
    opInfo.Type = CF_OPERATION_TYPE_TRANSFER_DATA;
    opInfo.ConnectionKey = FakeCloudProvider::GetConnectionKey();
    opInfo.TransferKey.QuadPart = transferKey;
    opParams.ParamSize = CF_SIZE_OF_OP_PARAM(TransferData);
    opParams.TransferData.CompletionStatus = completionStatus;
    opParams.TransferData.Buffer = transferData;
    opParams.TransferData.Offset.QuadPart = startingOffset;
    opParams.TransferData.Length.QuadPart = length;

    winrt::check_hresult(CfExecute(&opInfo, &opParams));     
    return S_OK;
}

在大约 9.3 GB 大小的同步根文件夹中只创建了一个占位符文件。创建此后,我双击它或右键单击并“始终保留在此设备上” - 结果相同。

结果是在最后一次调用TransferDataWindows 资源管理器文件进度后卡住了。它最终会超时,我点击“再试一次”,我里面的断点OnFetchData()被击中,文件进度仍然卡住。如果我取消转移,那么onCancelFetchData()它应该会被调用一次。后续尝试下载文件的其余部分将不再调用onFetchData()

如果我注释掉该if (0 != len % 4096) len = 4096 * (len / 4096 + 1);部分,那么我就会0x8007017c the cloud operation is invalid对上述其他症状感到恐惧。

我试过一个更小的~ 9.3 MB 的文件,它很顺利……还有什么可尝试的?

编辑

~100MB 和 ~1GB 大小也可以正常工作

CfExecute调用结果:

//[...] same output for all previous offsets except for the last call
TransferData method - offset: 1298137088, length: 50331648, syncStatBeforeCall: null, syncStatAfterCall: null, hresult: 0
TransferData method - offset: 1348468736, length: 50331648, syncStatBeforeCall: null, syncStatAfterCall: null, hresult: 0
TransferData method - offset: 1398800384, length: 11265024, syncStatBeforeCall: null, syncStatAfterCall: null, hresult: 8007017c

据我所知,null 适用于SyncStatus

同步状态

注意 此成员是 Windows 10 版本 1803 的新成员。

平台的当前同步状态。

平台在云文件占位符上的任何失败操作时查询此信息。如果结构可用,平台将使用提供的信息为用户构建更有意义和可操作的消息。平台会将这些信息保留在文件中,直到它的最后一个句柄消失。如果为空,平台将清除之前设置的同步状态,如果有的话。

- 编辑 -

HRESULT Placeholders::Create(_In_ PCWSTR destPath,
                          _In_ PCWSTR fileName,
                          _In_ CF_PLACEHOLDER_CREATE_FLAGS flags,
                          _In_ LONG64 fileSize,
                          _In_ DWORD fileAttributes,
                          _In_ LONG64  ftCreationTime,
                          _In_ LONG64  ftLastWriteTime,
                          _In_ LONG64  ftLastAccessTime,
                          _In_ LONG64  ftChangeTime)
{
    CF_PLACEHOLDER_CREATE_INFO cloudEntry;
        
    cloudEntry.FileIdentity = fileName;
    cloudEntry.FileIdentityLength = (DWORD)((wcslen(fileName)+1) * sizeof(WCHAR));
    cloudEntry.RelativeFileName = fileName;
    cloudEntry.Flags = flags;
    cloudEntry.FsMetadata.FileSize.QuadPart = fileSize;
    cloudEntry.FsMetadata.BasicInfo.FileAttributes = fileAttributes;
    cloudEntry.FsMetadata.BasicInfo.CreationTime.QuadPart = ftCreationTime;
    cloudEntry.FsMetadata.BasicInfo.LastWriteTime.QuadPart = ftLastWriteTime;
    cloudEntry.FsMetadata.BasicInfo.LastAccessTime.QuadPart = ftLastAccessTime;
    cloudEntry.FsMetadata.BasicInfo.ChangeTime.QuadPart = ftChangeTime;

    if ((fileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
    {
        cloudEntry.Flags |= CF_PLACEHOLDER_CREATE_FLAG_DISABLE_ON_DEMAND_POPULATION;
        cloudEntry.FsMetadata.FileSize.QuadPart = 0;
        cloudEntry.FileIdentity = nullptr;
    }

    try
    {
        wprintf(L"Creating placeholder for %sn", fileName);
        winrt::check_hresult(CfCreatePlaceholders(destPath, &cloudEntry, 1, CF_CREATE_FLAG_NONE, NULL));
    }
    catch (...)
    {
        // winrt::to_hresult() will eat the exception if it is a result of winrt::check_hresult,
        // otherwise the exception will get rethrown and this method will crash out as it should
        wprintf(L"Failed to create placeholder for %s with %08xn", fileName, static_cast<HRESULT>(winrt::to_hresult()));
        // Eating it here lets other files still get a chance. Not worth crashing the sample, but
        // certainly noteworthy for production code
        return static_cast<HRESULT>(winrt::to_hresult());
    }

    return S_OK;
}

Create(_T("C:SyncRootDT"), _T("file1"), CF_PLACEHOLDER_CREATE_FLAG_MARK_IN_SYNC,
            10000000000, FILE_ATTRIBUTE_NORMAL, 532657415, 532657415, 532657415, 532657415));

回答

我观察到类似的行为。高达 4Gb 的文件水合工作正常,但超过 4Gb 的文件总是卡住并因“云操作无效”异常而失败。我能够通过这个修复来克服它,但我使用了来自 CF_CALLBACK_INFO.FileSize 的完整文件长度,而不是 CF_CALLBACK_PARAMETERS.FETCHDATA.RequiredLength 和 OptionalLength。看起来在最近的 Windows 更新之后 OptionalLength 始终为零。我的代码在 .NET 中,但我想您可以轻松将其转换为 C++:

// Use a complete file size in case the file is over 4Gb
if (callbackInfo.FileSize > 0x100000000)
{
    requiredLength = callbackInfo.FileSize;
}


以上是Windows10文件云/同步提供程序API-TransferData问题的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>