Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Windows 8 et Windows Server 2012 présentent la possibilité pour les logiciels qui s’exécutent sur une machine virtuelle de détecter qu’un événement de décalage de temps peut se produire. Les événements de décalage de temps peuvent se produire à la suite d’une application d’une capture instantanée de machine virtuelle ou de la restauration d’une sauvegarde de machine virtuelle. Pour plus d’informations sur cette fonctionnalité, consultez le livre blanc ID de génération de machine virtuelle.
Conditions préalables
Pour utiliser l’identificateur de génération de machine virtuelle à partir d’une machine virtuelle, votre machine virtuelle doit être conforme aux éléments suivants.
La machine virtuelle doit s’exécuter sur un hyperviseur qui implémente la prise en charge des identificateurs de génération de machine virtuelle. Actuellement, voici les éléments suivants :
- Windows 8
- Windows Server 2012
- Microsoft Hyper-V Server 2012
La machine virtuelle doit exécuter un système d’exploitation invité qui prend en charge l’identificateur de génération de machine virtuelle. Actuellement, il s’agit des éléments suivants.
Les systèmes d’exploitation suivants prennent en charge nativement l’identificateur de génération de machine virtuelle.
- Windows 8
- Windows Server 2012
Le fonctionnement suivant peut être utilisé comme système d’exploitation invité si les services d’intégration Hyper-V de Windows 8 ou Windows Server 2012 sont installés.
- Windows Server 2008 R2 avec Service Pack 1 (SP1)
- Windows 7 avec Service Pack 1 (SP1)
- Windows Server 2008 avec Service Pack 2 (SP2)
- Windows Server 2003 R2
- Windows Server 2003 avec Service Pack 2 (SP2)
- Windows Vista avec Service Pack 2 (SP2)
- Windows XP avec Service Pack 3 (SP3)
Obtention de l’identificateur de génération de machine virtuelle
Pour obtenir par programmation l’identificateur de génération de machine virtuelle, procédez comme suit.
Note
Les éléments suivants doivent être exécutés avec des privilèges d’administrateur ou système pour fonctionner correctement.
Incluez le fichier d’en-tête « vmgenerationcounter.h » dans votre application. Le fichier d’en-tête contient les définitions suivantes :
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;Ouvrez un handle sur l’appareil « \\.\VmGenerationCounter » à l’aide de la fonction CreateFile. Vous pouvez également utiliser le gestionnaire PnP pour utiliser l’interface d’appareil GUID_DEVINTERFACE_VM_GENCOUNTER ({3ff2c92b-6598-4e60-8e1c-0ccf4927e319}). Ces objets ne sont pas présents si l’application n’est pas en cours d’exécution dans une machine virtuelle.
Envoyez le IOCTL_VMGENCOUNTER_READ IOCTL au pilote pour récupérer l’identificateur de génération.
La IOCTL_VMGENCOUNTER_READ IOCTL fonctionne dans l’un des deux modes, d’interrogation et pilotée par l’événement.
Pour émettre le IOCTL en mode d’interrogation, vous soumettez le IOCTL avec une mémoire tampon d’entrée de longueur nulle. En réponse à cela, le pilote récupère l’identificateur de génération actuel, l’écrit dans la mémoire tampon de sortie et termine le IOCTL.
Pour émettre l’IOCTL en mode piloté par les événements, envoyez le IOCTL avec une mémoire tampon d’entrée qui contient un identificateur de génération existant. En réponse à ce problème, le pilote attend que l’identificateur de génération actuel devienne différent de l’identificateur de génération qui a été transmis. Lorsque l’identificateur de génération change, le pilote écrit l’identificateur de génération actuel dans la mémoire tampon de sortie et termine le IOCTL.
Dans les deux modes, le format et la longueur de la mémoire tampon de sortie sont dictés par la structure VM_GENCOUNTER.
Le mode d’interrogation est pris en charge sur tous les systèmes d’exploitation invités répertoriés ci-dessus. Le mode piloté par les événements est pris en charge uniquement sur Windows Vista avec SP2, Windows Server 2008 avec SP2 et les systèmes d’exploitation ultérieurs. Sur les systèmes d’exploitation précédents, le IOCTL échoue avec le code d’erreur ERROR_NOT_SUPPORTED lorsqu’il est émis en mode piloté par les événements.
Il est possible que l’identificateur de génération change entre le moment où il est récupéré par le pilote et l’heure à laquelle le IOCTL est terminé. Cela peut entraîner la réception de données obsolètes par l’application cliente. Pour éviter cela, l’application cliente peut utiliser le mode piloté par les événements pour s’assurer qu’elle finira par en savoir plus sur les mises à jour apportées à l’identificateur de génération. En prenant l’identificateur actuel de l’application cliente comme entrée, le mode piloté par les événements évite les conditions de concurrence potentielles qui entraîneraient l’absence de notifications de l’appelant.
L’exemple de code suivant montre comment effectuer les actions ci-dessus pour obtenir l’identificateur de génération de machine virtuelle.
Note
Le code suivant doit être exécuté avec des privilèges d’administrateur ou système pour fonctionner correctement.
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;
};
Déterminer si un événement de décalage de temps s’est produit
Une fois que vous avez obtenu l’identificateur de génération de machine virtuelle, vous devez le stocker pour une utilisation ultérieure. Avant que votre application n’effectue une opération temporelle, telle que la validation d’une base de données, vous devez récupérer à nouveau l’identificateur de génération et le comparer à la valeur stockée. Si l’identificateur a changé, cela signifie qu’un événement de décalage de temps s’est produit et que votre application doit agir de manière appropriée.