Identificador de geração de máquina virtual

Windows 8 e Windows Server 2012 introduzem a capacidade de software em execução em uma máquina virtual para detectar que um evento de turno de tempo pode ter ocorrido. Eventos de turno de tempo podem ocorrer como resultado de um aplicativo de um instantâneo de máquina virtual ou da restauração de um backup de máquina virtual. Para obter mais informações sobre essa funcionalidade, consulte o white paper da ID de Geração de Máquina Virtual.

Pré-requisitos

Para usar o identificador de geração de máquina virtual de dentro de uma máquina virtual, sua máquina virtual deve estar em conformidade com o seguinte.

  • A máquina virtual deve estar em execução em um hipervisor que implemente o suporte para identificadores de geração de máquina virtual. Atualmente, estes são os seguintes:

    • Windows 8
    • Windows Server 2012
    • Microsoft Hyper-V Server 2012
  • A máquina virtual deve estar executando um sistema operacional convidado que tenha suporte para o identificador de geração de máquina virtual. Atualmente, estes são os seguintes.

    Os sistemas operacionais a seguir têm suporte nativo para o identificador de geração de máquina virtual.

    • Windows 8
    • Windows Server 2012

    A operação a seguir poderá ser usada como o sistema operacional convidado se os serviços de integração do Hyper-V de Windows 8 ou Windows Server 2012 estiverem instalados.

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

Obtendo o identificador de geração de máquina virtual

Para obter programaticamente o identificador de geração de máquina virtual, execute as etapas a seguir.

Observação

O seguinte deve ser executado com privilégios de administrador ou sistema para funcionar corretamente.

 

  1. Inclua o arquivo de cabeçalho "vmgenerationcounter.h" em seu aplicativo. O arquivo de cabeçalho contém estas definições:

    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. Abra um identificador para o dispositivo "\\.\VmGenerationCounter" usando a função CreateFile . Como alternativa, você pode usar o gerenciador PnP para consumir a interface do dispositivo GUID_DEVINTERFACE_VM_GENCOUNTER ({3ff2c92b-6598-4e60-8e1c-0ccf4927e319}). Esses objetos não estarão presentes se o aplicativo não estiver em execução em uma máquina virtual.

  3. Envie o IOCTL_VMGENCOUNTER_READ IOCTL para o driver para recuperar o identificador de geração.

    O IOCTL_VMGENCOUNTER_READ IOCTL opera em um dos dois modos, sondagem e eventos controlados.

    Para emitir o IOCTL no modo de sondagem, envie o IOCTL com um buffer de entrada de comprimento zero. Em resposta a isso, o driver recupera o identificador de geração atual, grava-o no buffer de saída e conclui o IOCTL.

    Para emitir o IOCTL no modo controlado por eventos, envie o IOCTL com um buffer de entrada que contém um identificador de geração existente. Em resposta a isso, o driver aguarda até que o identificador de geração atual se torne diferente do identificador de geração que foi passado. Quando o identificador de geração é alterado, o driver grava o identificador de geração atual no buffer de saída e conclui o IOCTL.

    Em ambos os modos, o formato e o comprimento do buffer de saída são ditados pela estrutura VM_GENCOUNTER .

    Há suporte para o modo de sondagem em todos os sistemas operacionais convidados listados acima. O modo controlado por eventos só tem suporte no Windows Vista com SP2, Windows Server 2008 com SP2 e sistemas operacionais posteriores. Em sistemas operacionais anteriores, o IOCTL falhará com o código de erro ERROR_NOT_SUPPORTED quando emitido no modo controlado por eventos.

    É possível que o identificador de geração altere entre o tempo em que ele é recuperado pelo driver e a hora em que o IOCTL é concluído. Isso pode fazer com que o aplicativo cliente receba dados obsoletos. Para evitar isso, o aplicativo cliente pode usar o modo controlado por eventos para garantir que ele eventualmente aprenderá sobre quaisquer atualizações para o identificador de geração. Ao usar o identificador atual do aplicativo cliente como entrada, o modo controlado por eventos evita possíveis condições de corrida que fariam com que o chamador perdesse as notificações.

O exemplo de código a seguir mostra como executar as ações acima para obter o identificador de geração de máquina virtual.

Observação

O código a seguir deve ser executado com privilégios de administrador ou sistema para funcionar corretamente.

 

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

Determinando se ocorreu um evento de turno de tempo

Depois de obter o identificador de geração de máquina virtual, você deve armazená-lo para uso futuro. Antes que seu aplicativo execute uma operação sensível ao tempo, como se comprometer com um banco de dados, você deve obter novamente o identificador de geração e compará-lo com o valor armazenado. Se o identificador tiver sido alterado, isso significa que ocorreu um evento de turno de tempo e seu aplicativo deve agir adequadamente.