Bezeichner der virtuellen Computergenerierung

Windows 8 und Windows Server 2012 die Möglichkeit für Software ein, die auf einem virtuellen Computer ausgeführt wird, um zu erkennen, dass ein Zeitverschiebungsereignis möglicherweise aufgetreten ist. Zeitverschiebungsereignisse können aufgrund einer Anwendung einer Momentaufnahme eines virtuellen Computers oder der Wiederherstellung einer virtuellen Computersicherung auftreten. Weitere Informationen zu dieser Funktionalität finden Sie in dem Whitepaper zur Virtuellen Computergenerierungs-ID.

Voraussetzungen

Um den Generierungsbezeichner des virtuellen Computers aus einem virtuellen Computer zu verwenden, muss Der virtuelle Computer den folgenden Anforderungen entsprechen.

  • Der virtuelle Computer muss auf einem Hypervisor ausgeführt werden, der unterstützung für virtuelle Computergenerierungsbezeichner implementiert. Derzeit sind dies die folgenden:

    • Windows 8
    • Windows Server 2012
    • Microsoft Hyper-V Server 2012
  • Der virtuelle Computer muss ein Gastbetriebssystem ausführen, das Unterstützung für den Bezeichner der virtuellen Computergenerierung hat. Derzeit sind dies die folgenden.

    Die folgenden Betriebssysteme unterstützen systemeigene Unterstützung für den Bezeichner der virtuellen Computergenerierung.

    • Windows 8
    • Windows Server 2012

    Der folgende Betrieb kann als Gastbetriebssystem verwendet werden, wenn die Hyper-V-Integrationsdienste von Windows 8 oder Windows Server 2012 installiert sind.

    • Windows Server 2008 R2 mit Service Pack 1 (SP1)
    • Windows 7 mit Service Pack 1 (SP1)
    • Windows Server 2008 mit Service Pack 2 (SP2)
    • Windows Server 2003 R2
    • Windows Server 2003 mit Service Pack 2 (SP2)
    • Windows Vista mit Service Pack 2 (SP2)
    • Windows XP mit Service Pack 3 (SP3)

Abrufen des Bezeichners der virtuellen Computergenerierung

Führen Sie die folgenden Schritte aus, um den Bezeichner der virtuellen Computergenerierung programmgesteuert abzurufen.

Hinweis

Das folgende Muss mit Administrator- oder Systemrechten ausgeführt werden, um ordnungsgemäß zu funktionieren.

 

  1. Fügen Sie die Kopfzeilendatei "vmgenerationcounter.h" in Ihre App ein. Die Kopfzeilendatei enthält folgende Definitionen:

    DEFINE_GUID(
        GUID_DEVINTERFACE_VM_GENCOUNTER,
        0x3ff2c92b, 
        0x6598, 
        0x4e60, 
        0x8e, 
        0x1c, 
        0x0c, 
        0xcf, 
        0x49, 
        0x27, 
        0xe3, 
        0x19);
    
    #define VM_GENCOUNTER_SYMBOLIC_LINK_NAME L"VmGenerationCounter"
    
    #define IOCTL_VMGENCOUNTER_READ CTL_CODE( \
        FILE_DEVICE_ACPI, \
        0x1, METHOD_BUFFERED, \
        FILE_READ_ACCESS | FILE_WRITE_ACCESS)
    
    typedef struct _VM_GENCOUNTER
    {
        ULONGLONG GenerationCount;
        ULONGLONG GenerationCountHigh;
    } VM_GENCOUNTER, *PVM_GENCOUNTER;
    
  2. Öffnen Sie einen Handle mit der CreateFile-Funktion auf dem Gerät "\\.\VmGenerationCounter". Alternativ können Sie den PnP-Manager verwenden, um die Geräteschnittstelle GUID_DEVINTERFACE_VM_GENCOUNTER zu nutzen ({3ff2c92b-6598-4e60-8e1c-0ccf4927e319}). Diese Objekte werden nicht vorhanden sein, wenn die App nicht auf einem virtuellen Computer ausgeführt wird.

  3. Senden Sie den IOCTL_VMGENCOUNTER_READ IOCTL an den Treiber, um den Generationsbezeichner abzurufen.

    Die IOCTL_VMGENCOUNTER_READ IOCTL arbeitet in einem von zwei Modi, Umfrage und Ereignisgesteuerten.

    Um das IOCTL im Umfragemodus zu stellen, übermitteln Sie das IOCTL mit einem Eingabepuffer von null Länge. Auf diese Weise ruft der Treiber den aktuellen Generation-Bezeichner ab, schreibt es in den Ausgabepuffer und schließt das IOCTL ab.

    Um das IOCTL im ereignisgesteuerten Modus zu beheben, übermitteln Sie das IOCTL mit einem Eingabepuffer, der einen vorhandenen Generationsbezeichner enthält. Als Reaktion darauf wartet der Treiber, bis sich der bezeichner der aktuellen Generation von dem Generationsbezeichner unterscheidet, der übergeben wurde. Wenn sich der Generationsbezeichner ändert, schreibt der Treiber den aktuellen Generation-Bezeichner in den Ausgabepuffer und schließt das IOCTL ab.

    In beiden Modi wird das Format und die Länge des Ausgabepuffers durch die VM_GENCOUNTER Struktur bestimmt.

    Der Abfragemodus wird auf allen oben aufgeführten Gastbetriebssystemen unterstützt. Der ereignisgesteuerte Modus wird nur auf Windows Vista mit SP2, Windows Server 2008 mit SP2 und späteren Betriebssystemen unterstützt. Bei früheren Betriebssystemen schlägt das IOCTL mit dem Fehlercode ERROR_NOT_SUPPORTED fehl, wenn er im ereignisgesteuerten Modus ausgestellt wird.

    Es ist möglich, dass der Generationsbezeichner zwischen dem Zeitpunkt, zu dem er vom Treiber abgerufen wird, und der Zeitpunkt, zu dem das IOCTL abgeschlossen ist, geändert werden kann. Dies kann dazu führen, dass die Client-App veraltete Daten empfängt. Um dies zu vermeiden, kann die Client-App den ereignisgesteuerten Modus verwenden, um sicherzustellen, dass es schließlich über alle Updates für den Generationsbezeichner informiert wird. Durch Das Verwenden des aktuellen Bezeichners der Client-App als Eingabe verhindert der ereignisgesteuerte Modus potenzielle Rennbedingungen, die dazu führen würden, dass der Anrufer Benachrichtigungen verpasst.

Im folgenden Codebeispiel wird gezeigt, wie Sie die oben genannten Aktionen ausführen, um den Bezeichner der virtuellen Computergenerierung abzurufen.

Hinweis

Der folgende Code muss mit Administrator- oder Systemrechten ausgeführt werden, um ordnungsgemäß zu funktionieren.

 

HRESULT GetVmCounter(bool fWaitForChange)
{
    BOOL success = FALSE;
    DWORD error = ERROR_SUCCESS;
    VM_GENCOUNTER vmCounterOutput = {0};
    DWORD size = 0;
    HANDLE handle = INVALID_HANDLE_VALUE;
    HRESULT hr = S_OK;

    handle = CreateFile(
        L"\\\\.\\" VM_GENCOUNTER_SYMBOLIC_LINK_NAME,
        GENERIC_READ | GENERIC_WRITE,
        FILE_SHARE_READ | FILE_SHARE_WRITE,
        NULL,
        OPEN_EXISTING,
        0,
        NULL);

    if (handle == INVALID_HANDLE_VALUE)
    {
        error = GetLastError();

        wprintf(
            L"Unable to open device %s. Error code = %d.", 
            VM_GENCOUNTER_SYMBOLIC_LINK_NAME, 
            error);

        hr = HRESULT_FROM_WIN32(error);

        goto Cleanup;
    }

    /*
    Call into the driver. 

    Because the 4th parameter to DeviceIoControl (nInBufferSize) is zero, this 
    is a polling request rather than an event-driven request.
    */
    success = DeviceIoControl(
        handle,
        IOCTL_VMGENCOUNTER_READ,
        NULL,
        0,
        &vmCounterOutput,
        sizeof(vmCounterOutput),
        &size,
        NULL);

    if (!success)
    {
        error = GetLastError();

        wprintf(L"Call IOCTL_VMGENCOUNTER_READ failed with %d.", error);

        hr = HRESULT_FROM_WIN32(error);

        goto Cleanup;
    }

    wprintf(
        L"VmCounterValue: %I64x:%I64x",
        vmCounterOutput.GenerationCount,
        vmCounterOutput.GenerationCountHigh);

    if (fWaitForChange)
    {
        /*
        Call into the driver again in event-driven mode. DeviceIoControl won't 
        return until the generation identifier has changed.
        */
        success = DeviceIoControl(
            handle,
            IOCTL_VMGENCOUNTER_READ,
            &vmCounterOutput,
            sizeof(vmCounterOutput),
            &vmCounterOutput,
            sizeof(vmCounterOutput),
            &size,
            NULL);

        if (!success)
        {
            error = GetLastError();

            wprintf(L"Call IOCTL_VMGENCOUNTER_READ failed with %d.", error);

            hr = HRESULT_FROM_WIN32(error);

            goto Cleanup;
        }

        wprintf(
            L"VmCounterValue changed to: %I64x:%I64x",
            vmCounterOutput.GenerationCount,
            vmCounterOutput.GenerationCountHigh);
    }

Cleanup:

    if (handle != INVALID_HANDLE_VALUE)
    {
        CloseHandle(handle);
    }

    return hr;
};

Ermitteln, ob ein Zeitverschiebungsereignis aufgetreten ist

Nachdem Sie den Bezeichner der virtuellen Computergenerierung erhalten haben, sollten Sie sie für zukünftige Verwendung speichern. Bevor Ihre App einen zeitgeschützten Vorgang ausführt, z. B. das Festlegen einer Datenbank, sollten Sie den Generationsbezeichner erneut abrufen und ihn mit dem gespeicherten Wert vergleichen. Wenn sich der Bezeichner geändert hat, bedeutet das, dass ein Zeitverschiebungsereignis aufgetreten ist, und Ihre App muss entsprechend handeln.