共用方式為


CfGetPlaceholderRangeInfoForHydration 函式 (cfapi.h)

取得佔位元檔案或資料夾的範圍資訊。 此範圍資訊與 CfGetPlaceholderRangeInfo 傳回的內容相同。 不過,它不會採用 fileHandle 作為參數。 相反地,它會使用 ConnectionKeyTransferKeyFileId 來識別要求範圍資訊的檔案和數據流。

平臺會將 ConnectionKeyTransferKeyFileId 提供給透過 CfConnectSyncRoot 註冊的所有回呼函式,提供者可以使用這些參數,從 CF_CALLBACK_TYPE_FETCH_DATA 回呼取得佔位符的範圍資訊,而不需要開啟檔案的句柄。

如果檔案不是雲端檔案佔位符,API 將會失敗。 成功時,會根據所要求的特定 InfoClass 傳回範圍資訊。

注意

只有當從 CfGetPlatformInfo 取得的 是0x600或更新版本時PlatformVersion.IntegrationNumber,才可使用此 API。

語法

HRESULT CfGetPlaceholderRangeInfoForHydration(
  [in]            CF_CONNECTION_KEY               ConnectionKey,
  [in]            CF_TRANSFER_KEY                 TransferKey,
  [in]            LARGE_INTEGER                   FileId,
  [in]            CF_PLACEHOLDER_RANGE_INFO_CLASS InfoClass,
  [in]            LARGE_INTEGER                   StartingOffset,
  [in]            LARGE_INTEGER                   RangeLength,
  [out]           PVOID                           InfoBuffer,
  [in]            DWORD                           InfoBufferSize,
  [out, optional] PDWORD                          InfoBufferWritten
);

參數

[in] ConnectionKey

CfConnectSyncRoot 針對同步提供者所管理的同步根目錄所建立的不透明句柄。 它也會在CF_CALLBACK_TYPE_FETCH_DATA回呼和其他回呼的CF_CALLBACK_INFO中傳回。

[in] TransferKey

已叫用 CF_CALLBACK_TYPE_FETCH_DATA 回呼之佔位符檔案的不透明句柄。 它也會在CF_CALLBACK_TYPE_FETCH_DATA回呼的CF_CALLBACK_INFO中傳回。 如果 API 未從CF_CALLBACK_TYPE_FETCH_DATA回呼叫用,則 CfGetTransferKey 也可以取得此動作。

[in] FileId

要服務之佔位元檔案/目錄的64位檔系統維護全磁碟區唯一標識元。 如同 TransferKey,這會在CF_CALLBACK_TYPE_FETCH_DATA和其他回呼的CF_CALLBACK_INFO中傳回,如此提供者就不需要再次擷取它。

[in] InfoClass

佔位元數據範圍的類型。 這個值可以是下列值之一:

Description
CF_PLACEHOLDER_RANGE_INFO_ONDISK 磁碟上的數據是檔案中實體存在的數據。 這是一組其他類型的範圍。
CF_PLACEHOLDER_RANGE_INFO_VALIDATED 已驗證的數據是目前與雲端同步的磁碟數據子集。
CF_PLACEHOLDER_RANGEINFO_MODIFIED 已修改的數據是目前未與雲端同步的磁碟數據子集 (,也就是已修改或附加。)

[in] StartingOffset

數據範圍的起點位移。 StartingOffsetRangeLength 指定佔位符檔案中的範圍,其資訊如 InfoClass 參數所描述

[in] RangeLength

數據範圍的長度。 提供者可以指定 CF_EOFRangeLength ,以指出要求資訊的範圍是從 StartingOffset 到檔案結尾。

[out] InfoBuffer

將接收數據的緩衝區指標。 緩衝區是 CF_FILE_RANGE 結構的數位,這些結構是位移/長度組,描述要求的範圍。

[in] InfoBufferSize

InfoBuffer 的長度,以位元組為單位。

[out, optional] InfoBufferWritten

接收 InfoBuffer 中傳回的位元組數目。

傳回值

如果函式成功,則會傳 S_OK回 。 否則,它會傳回 HRESULT 錯誤碼。 下表列出一些常見的錯誤碼:

錯誤碼 意義
HRESULT_FROM_WIN32 ( ERROR_HANDLE_EOF ) 這表示 StartingOffset>= 檔案結尾的位置。
HRESULT_FROM_WIN32 ( ERROR_MORE_DATA ) 這表示下一 個CF_FILE_RANGE 專案不適用於提供的緩衝區。 呼叫端應該確認是否收到任何專案,或使用傳回 的 InfoBufferWritten 值。

備註

雖然查詢佔位符之已凍結檔案範圍的 API 已經存在,但需要新的 API 來改善平臺的可靠性。

現有的 API CfGetPlaceholderRangeInfo 需要檔案的開啟句柄,然後使用該句柄觸發 FSCTL_HSM_CONTROL 。 提供者/同步引擎通常會使用此 API 來評估哪些部分的檔案不會從篩選條件叫用 的CF_CALLBACK_TYPE_FETCH_DATA 回呼內容中凍結,以滿足 IO。

當提供者/同步引擎嘗試開啟要當做參數傳遞至 CfGetPlaceholderRangeInfo 的句柄時,IO 堆棧中的迷你篩選可能會對檔案發出數據掃描。 或者,迷你篩選器可能會封鎖 CfGetPlaceholderRangeInfo 在內部觸發的FSCTL_HSM_CONTROL

cldflt 篩選是設計成只叫用每個必要檔案範圍的一個CF_CALLBACK_TYPE_FETCH_DATA回呼,以便將檔案凍結。 由於上述任一案例,數據掃描會停滯在原始 CF_CALLBACK_TYPE_FETCH_DATA 後面,或 CF_CALLBACK_TYPE_FETCH_DATA 停滯在封鎖 的 FSCTL 後方。 這會導致凍結路徑中的死結。

因此,需要此 API。 它會執行與 CfGetPlaceholderRangeInfo 相同的功能,但會使用略過中繼 IO 堆棧的篩選訊息埠直接與篩選通訊。 因此,任何中繼迷你篩選器都無法妨礙 CreateFileFSCTL_HSM_CONTROL

請注意,呼叫端一律會透過 CfConnectSyncRoot 取得 ConnectionKey。 它可以透過 CfGetTransferKey 取得 TransferKey,並使用 GetFileInformationByHandle 取得 FileId。 但此方法需要開啟檔案的句柄,因此與使用 CfGetPlaceholderRangeInfo 並無不同。

總而言之,當 CF_CALLBACK_TYPE_FETCH_DATA 回呼的內容需要範圍資訊時,應該使用此 API。 在所有其他情況下,包括提供者想要解除檔案凍結,而不需篩選條件要求時,應該使用 CfGetPlaceholderRangeInfo 。 平臺無法辨識特定內容中呼叫的 API,因此 onus 位於提供者/同步處理引擎上,以執行正確的動作。

範例

這是一個簡單的範例,其中函式會傳遞足以一次只擷取一個CF_FILE_RANGE專案的InfoBuffer。 在實務上,呼叫端可以傳遞 InfoBuffer ,以根據 API 的調用對應至多個 CF_FILE_RANGE 專案。 如有需要 ,可以使用 錯誤碼HRESULT_FROM_WIN32 ( ERROR_MORE_DATA ) 传递较大的缓冲区。

#include <cfapi.h>

// ******************************************************************************************************
// From within the CF_CALLBACK_TYPE_FETCH_DATA Callback, the provider can use
// g_PlatformInfo.IntegrationNumber to see if the new API is supported. If it is, the provider can pass
// ConnectionKey, TransferKey and FileId along with other parameters to obtain information about file
// ranges which have already been hydrated.
// *******************************************************************************************************

// The provider could obtain file ranges that are hydrated like this:
std::vector<CF_FILE_RANGE> hydratedRanges = GetFileRangesFromCallback( CallbackInfo->ConnectionKey,
                                                                       CallbackInfo->TransferKey,
                                                                       CallbackInfo->FileId,
                                                                       CF_PLACEHOLDER_RANGE_INFO_ONDISK
                                                                       0,
                                                                       CF_EOF);

// Based on these hydratedRanges, the provider can chose to hydrate only ranges which aren’t on the disk.

// ******************************************************************************************************
// Implementation of a function that eventually calls this API.
// ******************************************************************************************************

typedef HRESULT( __stdcall* t_CfGetPlaceholderRangeInfoForHydration )(
    CF_CONNECTION_KEY ConnectionKey,
    CF_TRANSFER_KEY TransferKey,
    LARGE_INTEGER FileId,
    CF_PLACEHOLDER_RANGE_INFO_CLASS InfoClass,
    LARGE_INTEGER StartingOffset,
    LARGE_INTEGER RangeLength,
    PVOID InfoBuffer,
    DWORD InfoBufferSize,
    PDWORD InfoBufferWritten );

t_CfGetPlaceholderRangeInfoForHydration _CfGetPlaceholderRangeInfoForHydration = nullptr;

std::vector<CF_FILE_RANGE>
GetFileRangesFromCallback( CF_CONNECTION_KEY ConnectionKey,
                           CF_TRANSFER_KEY TransferKey,
                           LARGE_INTEGER FileId,
                           CF_PLACEHOLDER_RANGE_INFO_CLASS RangeInfoClass,
                           long long StartOffset,
                           long long Length,
                           PBOOLEAN UseOldAPI )
{

    long long StartOffset = 0;
    CF_FILE_RANGE fileRange;
    long long Length = 0;
    LARGE_INTEGER queryOffset = ll2li( StartOffset );
    LARGE_INTEGER queryLength = ll2li( Length );
    DWORD inforBufferWritten = 0;

    // This will contain all the hydrated ranges in the file if the function succeeds.
    std::vector<CF_FILE_RANGE> ranges;
    bool stop = false;

    CF_PLATFORM_INFO platformInfo;

    hr = (CfGetPlatformInfo( &platformInfo ));
    if(FAILED(hr)) {
        *UseOldAPI = TRUE;
        return ranges; //empty.
    }

    if (platformInfo.IntegrationNumber < 600) {
        *UseOldAPI = TRUE;
        return ranges; //empty.
    }

    wil::unique_hmodule CloudFilesApi( LoadLibrary( L"cldapi.dll" ) );
    THROW_LAST_ERROR_IF_NULL( CloudFilesApi );

    _CfGetPlaceholderRangeInfoForHydration = reinterpret_cast<t_CfGetPlaceholderRangeInfoForHydration>(
            GetProcAddress( CloudFilesApi.get(), "CfGetPlaceholderRangeInfoForHydration" ) );
    THROW_LAST_ERROR_IF_NULL( _CfGetPlaceholderRangeInfoForHydration );

    while ( !stop ) {

        hr = _CfGetPlaceholderRangeInfoForHydration ( ConnectionKey,
                                                      TransferKey,
                                                      FileId,
                                                      RangeInfoClass,
                                                      queryOffset,
                                                      queryLength,
                                                      &fileRange,
                                                      sizeof( fileRange ),
                                                      &infoBufferWritten );

        if ( hr == HRESULT_FROM_WIN32( ERROR_HANDLE_EOF ) ||
             hr == HRESULT_FROM_WIN32( ERROR_MORE_DATA ) ) {

            // We need to break the loop only if there is no more data.
            if ( hr == HRESULT_FROM_WIN32( ERROR_HANDLE_EOF ) ) {
                stop = true;
            }

            hr = S_OK;
        }

        if ( FAILED( hr ) || infoBufferWritten == 0 ) {
            return ranges;
        }

        ranges.push_back( fileRange );
        queryOffset.QuadPart = fileRange.StartingOffset.QuadPart + fileRange.Length.QuadPart;

        if ( Length != CF_EOF && queryOffset.QuadPart >= ( StartOffset + Length ) ) {
            stop = true;
        } else if ( Length != CF_EOF) {
            // Update the new query length
            queryLength.QuadPart = StartOffset + Length - queryOffset.QuadPart
        
            if ( queryLength.QuadPart <= 0 ) {
                stop = true;
            }
        }
    }

    return ranges;
}

規格需求

需求
標頭 cfapi.h

另請參閱

CF_PLACEHOLDER_RANGE_INFO_CLASS

CfGetPlaceholderRangeInfo

CfConnectSyncRoot

CfGetPlatformInfo

CfGetTransferKey