共用方式為


CfGetPlaceholderRangeInfoForHydration 函式 (cfapi.h)

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

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

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

備註

只有在從 CfGetPlatformInfo0x600 取得的 API 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,也可以由 CfGetTransferKey 取得 CF_CALLBACK_TYPE_FETCH_DATA

[in] FileId

要服務的預留位置檔案/目錄的 64 位元檔案系統維護的磁碟區範圍唯一 ID。 與 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 錯誤碼。 下表列出一些常見的錯誤碼:

錯誤碼 Meaning
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,因此提供者/同步處理引擎有責任執行正確的動作。

範例

這是一個簡單的範例,其中函數傳遞的 InfoBuffer 足以一次只擷取一個 CF_FILE_RANGE 項目。 實際上,呼叫端可以傳遞一個 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;
}

需求

Requirement 價值觀
Header cfapi.h
Library cldapi.lib

另請參閱

CF_PLACEHOLDER_RANGE_INFO_CLASS

CfGet預留位置範圍資訊

CfConnectSyncRoot

CfGet平台資訊

CfGetTransferKey