Nuta
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować się zalogować lub zmienić katalog.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
W systemach Windows 8 i Windows Server 2012 wprowadzono możliwość oprogramowania uruchomionego na maszynie wirtualnej w celu wykrycia, że mogło wystąpić zdarzenie zmiany czasu. Zdarzenia zmiany czasu mogą wystąpić w wyniku zastosowania migawki maszyny wirtualnej lub przywrócenia kopii zapasowej maszyny wirtualnej. Aby uzyskać więcej informacji na temat tej funkcji, zobacz oficjalny dokument Identyfikator generacji maszyny wirtualnej.
Warunki wstępne
Aby użyć identyfikatora generowania maszyny wirtualnej z poziomu maszyny wirtualnej, maszyna wirtualna musi być zgodna z następującymi wymaganiami.
Maszyna wirtualna musi być uruchomiona w funkcji hypervisor, która implementuje obsługę identyfikatorów generowania maszyn wirtualnych. Obecnie są to następujące elementy:
- Windows 8
- Windows Server 2012
- Microsoft Hyper-V Server 2012
Maszyna wirtualna musi mieć uruchomiony system operacyjny gościa z obsługą identyfikatora generowania maszyn wirtualnych. Obecnie są to następujące elementy.
Następujące systemy operacyjne mają natywną obsługę identyfikatora generowania maszyn wirtualnych.
- Windows 8
- Windows Server 2012
Następujące działanie może służyć jako system operacyjny gościa, jeśli są zainstalowane usługi integracji Hyper-V z systemu Windows 8 lub Windows Server 2012.
- Windows Server 2008 R2 z dodatkiem Service Pack 1 (SP1)
- Windows 7 z dodatkiem Service Pack 1 (SP1)
- Windows Server 2008 z dodatkiem Service Pack 2 (SP2)
- Windows Server 2003 R2
- Windows Server 2003 z dodatkiem Service Pack 2 (SP2)
- Windows Vista z dodatkiem Service Pack 2 (SP2)
- Windows XP z dodatkiem Service Pack 3 (SP3)
Uzyskiwanie identyfikatora generowania maszyny wirtualnej
Aby programowo uzyskać identyfikator generowania maszyny wirtualnej, wykonaj następujące kroki.
Nuta
Aby działać poprawnie, należy uruchomić następujące polecenie z uprawnieniami administratora lub systemu.
Uwzględnij plik nagłówka "vmgenerationcounter.h" w aplikacji. Plik nagłówka zawiera następujące definicje:
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;Otwórz dojście do urządzenia "\\.\VmGenerationCounter" przy użyciu funkcji CreateFile. Alternatywnie możesz użyć menedżera PnP do korzystania z interfejsu urządzenia GUID_DEVINTERFACE_VM_GENCOUNTER ({3ff2c92b-6598-4e60-8e1c-0ccf4927e319}). Te obiekty nie będą obecne, jeśli aplikacja nie jest uruchomiona na maszynie wirtualnej.
Wyślij IOCTL_VMGENCOUNTER_READ IOCTL do sterownika, aby pobrać identyfikator generacji.
IOCTL_VMGENCOUNTER_READ IOCTL działa w jednym z dwóch trybów, sondowaniei sterowane zdarzeniami.
Aby wydać IOCTL w trybie sondowania, należy przesłać IOCTL z buforem wejściowym o zerowej długości. W odpowiedzi na to sterownik pobiera bieżący identyfikator generacji, zapisuje go w buforze wyjściowym i kończy IOCTL.
Aby wydać IOCTL w trybie sterowanym zdarzeniami, prześlij IOCTL z buforem wejściowym zawierającym istniejący identyfikator generacji. W odpowiedzi na to sterownik czeka, aż bieżący identyfikator generacji będzie inny niż identyfikator generacji, który został przekazany. Gdy identyfikator generacji zmieni się, sterownik zapisuje bieżący identyfikator generacji w buforze wyjściowym i kończy IOCTL.
W obu trybach format i długość buforu wyjściowego są dyktowane przez strukturę VM_GENCOUNTER.
Tryb sondowania jest obsługiwany we wszystkich systemach operacyjnych gościa wymienionych powyżej. Tryb sterowany zdarzeniami jest obsługiwany tylko w systemie Windows Vista z dodatkiem SP2, Windows Server 2008 z dodatkiem SP2 i nowszymi systemami operacyjnymi. We wcześniejszych systemach operacyjnych IOCTL zakończy się niepowodzeniem z kodem błędu ERROR_NOT_SUPPORTED w przypadku wystawienia w trybie sterowania zdarzeniami.
Istnieje możliwość zmiany identyfikatora generacji między czasem pobierania przez sterownik a czasem ukończenia IOCTL. Może to spowodować, że aplikacja kliencka odbiera nieaktualne dane. Aby tego uniknąć, aplikacja kliencka może używać trybu sterowanego zdarzeniami, aby upewnić się, że w końcu dowie się o wszelkich aktualizacjach identyfikatora generacji. Biorąc bieżący identyfikator aplikacji klienckiej jako dane wejściowe, tryb sterowany zdarzeniami pozwala uniknąć potencjalnych warunków wyścigu, które mogłyby spowodować, że obiekt wywołujący przegapi powiadomienia.
Poniższy przykład kodu pokazuje, jak wykonać powyższe akcje w celu uzyskania identyfikatora generowania maszyny wirtualnej.
Nuta
Aby działać poprawnie, należy uruchomić następujący kod z uprawnieniami administratora lub systemu.
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;
};
Określanie, czy wystąpiło zdarzenie zmiany czasu
Po uzyskaniu identyfikatora generowania maszyny wirtualnej należy zapisać go do użytku w przyszłości. Zanim aplikacja wykona operację wrażliwą na czas, taką jak zatwierdzenie w bazie danych, należy ponownie uzyskać identyfikator generacji i porównać ją z przechowywaną wartością. Jeśli identyfikator uległ zmianie, oznacza to, że wystąpiło zdarzenie zmiany czasu, a aplikacja musi działać odpowiednio.