Nota
O acesso a esta página requer autorização. Podes tentar iniciar sessão ou mudar de diretório.
O acesso a esta página requer autorização. Podes tentar mudar de diretório.
O Windows 8 e o Windows Server 2012 introduzem a capacidade de o software em execução em uma máquina virtual detetar que um evento de mudança de hora pode ter ocorrido. Os eventos de deslocamento 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 Virtual Machine Generation ID.
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, são os seguintes:
- Janelas 8
- Windows Server 2012
- Servidor Hyper-V Microsoft 2012
A máquina virtual deve estar executando um sistema operacional convidado que tenha suporte para o identificador de geração da máquina virtual. Atualmente, estes são os seguintes.
Os seguintes sistemas operacionais têm suporte nativo para o identificador de geração de máquina virtual.
- Janelas 8
- Windows Server 2012
O sistema operacional a seguir pode ser usado como o sistema operacional convidado se os serviços de integração Hyper-V do 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 da máquina virtual
Para obter programaticamente o identificador de geração da 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.
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;Abra um identificador para o dispositivo "\\.\VmGenerationCounter" usando a funçãoCreateFile. 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 sendo executado em uma máquina virtual.
Envie o IOCTL IOCTL_VMGENCOUNTER_READ para o driver para recuperar o identificador de geração.
O IOCTL_VMGENCOUNTER_READ IOCTL opera em um dos dois modos, pollinge evento impulsionado.
Para emitir a IOCTL no modo de sondagem, envie a 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 a IOCTL no modo controlado por eventos, envie a IOCTL com um buffer de entrada que contenha um identificador de geração existente. Em resposta a isso, o driver espera 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 muda, 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.
O modo de sondagem é suportado em todos os sistemas operacionais convidados listados acima. O modo controlado por eventos é suportado apenas 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 mude entre o momento em que é recuperado pelo condutor e o momento 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 aprenda sobre quaisquer atualizações para o identificador de geração. Ao tomar 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 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;
};
Determinar se ocorreu um evento de mudança de horário
Depois de obter o identificador de geração da máquina virtual, você deve armazená-lo para uso futuro. Antes que seu aplicativo execute uma operação sensível ao tempo, como confirmar 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 mudança de hora e que seu aplicativo deve agir adequadamente.