CfGetPlaceholderRangeInfoForHydration-Funktion (cfapi.h)

Ruft Bereichsinformationen zu einer Platzhalterdatei oder einem Ordner ab. Diese Bereichsinformationen sind identisch mit den Rückgaben von CfGetPlaceholderRangeInfo . Es wird jedoch kein fileHandle als Parameter verwendet. Stattdessen werden ConnectionKey, TransferKey und FileId verwendet, um die Datei und den Stream zu identifizieren, für den Bereichsinformationen angefordert werden.

Die Plattform stellt ConnectionKey, TransferKey und FileId für alle Rückruffunktionen bereit, die über CfConnectSyncRoot registriert sind, und der Anbieter kann diese Parameter verwenden, um Bereichsinformationen über einen Platzhalter aus dem CF_CALLBACK_TYPE_FETCH_DATA Rückruf abzurufen, ohne dass ein Handle für die Datei geöffnet werden muss.

Wenn die Datei kein Platzhalter für Clouddateien ist, schlägt die API fehl. Bei Erfolg werden Bereichsinformationen entsprechend der spezifischen angeforderten InfoClass zurückgegeben.

Hinweis

Diese API ist nur verfügbar, wenn die PlatformVersion.IntegrationNumber von CfGetPlatformInfo abgerufene oder höher ist 0x600 .

Syntax

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
);

Parameter

[in] ConnectionKey

Ein undurchsichtiges Handle, das von CfConnectSyncRoot für einen Synchronisierungsstamm erstellt wurde, der vom Synchronisierungsanbieter verwaltet wird. Sie wird auch in CF_CALLBACK_INFO im CF_CALLBACK_TYPE_FETCH_DATA Rückruf und anderen Rückrufen zurückgegeben.

[in] TransferKey

Das undurchsichtige Handle für die Platzhalterdatei, für die CF_CALLBACK_TYPE_FETCH_DATA Rückruf aufgerufen wurde. Sie wird auch in CF_CALLBACK_INFO im CF_CALLBACK_TYPE_FETCH_DATA-Rückruf zurückgegeben. Dies kann alternativ von CfGetTransferKey abgerufen werden, wenn die API nicht über CF_CALLBACK_TYPE_FETCH_DATA Rückruf aufgerufen wird.

[in] FileId

Eine vom Dateisystem verwaltete 64-Bit-volumeweite eindeutige ID der zu wartenden Platzhalterdatei/des zu wartenden Verzeichnisses. Wie TransferKey wird dies in CF_CALLBACK_INFO im CF_CALLBACK_TYPE_FETCH_DATA und anderen Rückrufen zurückgegeben, sodass der Anbieter sie nicht erneut abrufen muss.

[in] InfoClass

Typen des Bereichs von Platzhalterdaten. Der Wert kann in folgenden Formen vorliegen:

Wert BESCHREIBUNG
CF_PLACEHOLDER_RANGE_INFO_ONDISK Daten auf dem Datenträger sind Daten, die physisch in der Datei vorhanden sind. Dies ist eine Supermenge anderer Arten von Bereichen.
CF_PLACEHOLDER_RANGE_INFO_VALIDATED Überprüfte Daten sind eine Teilmenge der Daten auf dem Datenträger, die derzeit mit der Cloud synchronisiert sind.
CF_PLACEHOLDER_RANGEINFO_MODIFIED Geänderte Daten sind eine Teilmenge der Daten auf dem Datenträger, die derzeit nicht mit der Cloud synchronisiert sind (d. h. entweder geändert oder angefügt).

[in] StartingOffset

Offset des Startpunkts des Datenbereichs. StartingOffset und RangeLength geben einen Bereich in der Platzhalterdatei an, dessen Informationen gemäß der Beschreibung durch den InfoClass-Parameter angefordert werden.

[in] RangeLength

Länge des Datenbereichs. Ein Anbieter kann für RangeLength angebenCF_EOF, um anzugeben, dass der Bereich, für den Informationen angefordert werden, von StartingOffset bis zum Ende der Datei liegt.

[out] InfoBuffer

Zeiger auf einen Puffer, der die Daten empfängt. Der Puffer ist ein Array von CF_FILE_RANGE-Strukturen , bei denen es sich um Offset-Länge-Paare handelt, die die angeforderten Bereiche beschreiben.

[in] InfoBufferSize

Die Länge von InfoBuffer in Bytes.

[out, optional] InfoBufferWritten

Empfängt die Anzahl der in InfoBuffer zurückgegebenen Bytes.

Rückgabewert

Wenn diese Funktion erfolgreich ist, wird zurückgegeben S_OK. Andernfalls wird ein Fehlercode HRESULT zurückgegeben. Einige häufige Fehlercodes sind in der folgenden Tabelle aufgeführt:

Fehlercode Bedeutung
HRESULT_FROM_WIN32( ERROR_HANDLE_EOF ) Dies bedeutet, dass StartingOffset> = die Position des Endes der Datei ist.
HRESULT_FROM_WIN32( ERROR_MORE_DATA ) Dies bedeutet, dass der nächste CF_FILE_RANGE Eintrag nicht in den bereitgestellten Puffer passt. Der Aufrufer sollte mithilfe des zurückgegebenen InfoBufferWritten-Werts überprüfen, ob ein Eintrag empfangen wird oder nicht.

Hinweise

Während bereits eine API zum Abfragen von aktivierten Dateibereichen eines Platzhalters vorhanden ist, wurde eine neue API benötigt, um die Zuverlässigkeit der Plattform zu verbessern.

Die vorhandene API CfGetPlaceholderRangeInfo erfordert ein geöffnetes Handle für eine Datei und löst dann mithilfe dieses Handles eine FSCTL_HSM_CONTROL aus. Anbieter/Synchronisierungs-Engines verwenden diese API normalerweise, um zu bewerten, welche Teile der Datei nicht aus dem Kontext eines CF_CALLBACK_TYPE_FETCH_DATA Rückrufs stammen, der vom Filter aufgerufen wird, um die Datei zu hydratisieren, um eine E/A-Anforderung zu erfüllen.

Ein Minifilter im E/A-Stapel kann eine Datenüberprüfung für die Datei ausgeben, wenn der Anbieter/die Synchronisierungs-Engine versucht, ein Handle für die Datei zu öffnen, die als Parameter an CfGetPlaceholderRangeInfo übergeben werden soll. Alternativ kann ein Minifilter die FSCTL_HSM_CONTROL blockieren, die CfGetPlaceholderRangeInfo intern auslöst.

Der cldflt-Filter ist so konzipiert, dass nur ein CF_CALLBACK_TYPE_FETCH_DATA Rückruf pro erforderlichem Dateibereich aufgerufen wird, um die Datei zu aktivieren. Aufgrund eines der oben genannten Fälle bleibt entweder die Datenüberprüfung hinter dem ursprünglichen CF_CALLBACK_TYPE_FETCH_DATA hängen, oder die CF_CALLBACK_TYPE_FETCH_DATA bleibt hinter der blockierten FSCTL hängen. Dies führt zu einem Deadlock im Flüssigkeitspfad.

Daher ist diese API erforderlich. Es führt die gleiche Funktionalität wie CfGetPlaceholderRangeInfo aus, kommuniziert jedoch direkt mit dem Filter über Filternachrichtenports, die den zwischengeschalteten E/A-Stapel umgehen. Daher kann kein Mini-Zwischenfilter die CreateFile - oder die FSCTL_HSM_CONTROL behindern.

Beachten Sie, dass der Aufrufer immer über den ConnectionKey verfügt, der über CfConnectSyncRoot abgerufen wurde. Es kann TransferKey über CfGetTransferKey abrufen und FileId mithilfe von GetFileInformationByHandle abrufen. Dieser Ansatz erfordert jedoch ein Handle, das für die Datei geöffnet werden soll, und unterscheidet sich daher nicht von der Verwendung von CfGetPlaceholderRangeInfo.

Zusammenfassend sollte diese API verwendet werden, wenn Bereichsinformationen aus dem Kontext eines CF_CALLBACK_TYPE_FETCH_DATA Rückrufs benötigt werden. In allen anderen Fällen, einschließlich, wenn der Anbieter die Datei hydratisieren möchte, ohne vom Filter angefordert zu werden, sollte CfGetPlaceholderRangeInfo verwendet werden. Die Plattform kann nicht erkennen, welche API in einem bestimmten Kontext aufgerufen wird, und daher befindet sich der Anbieter bzw. die Synchronisierungs-Engine, um das Richtige zu tun.

Beispiele

Dies ist ein einfaches Beispiel, bei dem die Funktion einen InfoBuffer übergibt, der ausreicht, um jeweils nur einen CF_FILE_RANGE Eintrag abzurufen. In der Praxis könnte der Aufrufer einen InfoBuffer übergeben, der mehreren CF_FILE_RANGE Einträgen pro Aufruf der API entsprechen könnte. Fehlercode HRESULT_FROM_WIN32( ERROR_MORE_DATA ) kann verwendet werden, um bei Bedarf einen größeren Puffer zu übergeben.

#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;
}

Anforderungen

Anforderung Wert
Header cfapi.h

Weitere Informationen

CF_PLACEHOLDER_RANGE_INFO_CLASS

CfGetPlaceholderRangeInfo

CfConnectSyncRoot

CfGetPlatformInfo

CfGetTransferKey