Notatka
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
GUID_DEVINTERFACE_DISK identyfikuje klasę interfejsu urządzenia dysku. Sterowniki klasy dysków dostarczone przez system rejestrują wystąpienia tej klasy dla udostępnianych dysków. Wyliczanie jego włączonych wystąpień to niezależny od stosu sposób odnajdywania ścieżek urządzeń dyskowych: zarówno starszy stos, jak i natywny stos NVMe udostępniają tę klasę interfejsu.
Dlatego należy wyliczyć identyfikator GUID interfejsu zamiast opierać się na identyfikatorze GUID klasy konfiguracji, takiego jak GUID_DEVCLASS_DISKDRIVE, który nie jest gwarantowany jako niezależny od stosu.
Identyfikator GUID interfejsu a identyfikator GUID klasy urządzenia
GUID_DEVINTERFACE_DISK i GUID_DEVCLASS_DISKDRIVE odpowiadają na różne pytania i nie są zamienne:
-
GUID_DEVINTERFACE_DISKidentyfikuje klasę interfejsu, a nie pojedynczą ścieżkę urządzenia. Wyliczanie jego włączonych wystąpień zwraca ścieżki linku symbolicznego, które aplikacje mogą przekazywać do metody CreateFileW. Wynikowy uchwyt może służyć do operacji obsługiwanych przez dysk docelowy, z zastrzeżeniem żądanych praw dostępu i odpowiednich uprawnień. Ścieżka wyliczona w procesie enumeracji nie jest gwarancją, że otwarcie dysku powiedzie się: urządzenie może zostać usunięte lub stać się niedostępne przed ukończeniem żądania otwarcia. -
GUID_DEVCLASS_DISKDRIVEto klasa konfiguracji urządzenia używana przez PnP/SetupAPI do instalacji i klasyfikacji urządzeń, takich jak instalacja sterowników, grupowanie w Menedżerze urządzeń, dopasowywanie INF i podobne zadania obsługi. Instancja urządzenia należąca do tej klasy konfiguracji nie ma gwarancji, że udostępnia interfejs, który można otworzyć, a wyliczanie według klasy konfiguracji nie mówi nic o tym, które interfejsy funkcjonalne, o ile w ogóle istnieją, ta instancja urządzenia obecnie udostępnia. - Starszy stos dysku (
disk.sys/classpnp.sys) używa klasy konfiguracjiGUID_DEVCLASS_DISKDRIVE, a stos natywnego nvme (nvmedisk.sys) używa własnej, innej klasy konfiguracji{75416e63-5912-4dfa-ae8f-3efaccaffb14}. Wyliczenie tylkoGUID_DEVCLASS_DISKDRIVEspowodowałoby więc pominięcie każdego dysku zarządzanego przez natywny stos NVMe.GUID_DEVINTERFACE_DISKnie ma tej luki, ponieważ oba stosy rejestrują ten sam interfejs dla każdego dysku, którym zarządzają.
Zakres wyliczenia
Ten przykład wykonuje jednorazowe wyliczanie aktualnie włączonych interfejsów urządzeń dyskowych. Nie wylicza woluminów ani liter dysku, a zwracana lista nie jest stale utrzymywanym spisem.
CM_GET_DEVICE_INTERFACE_LIST_PRESENT powoduje wybranie interfejsów obecnych/włączonych. Nie wskazuje, czy dysk jest w trybie online w narzędziu Zarządzanie dyskami.
W przypadku długotrwałej aplikacji, która śledzi podłączenia i odłączenia, zarejestruj powiadomienia interfejsu urządzenia za pomocą CM_Register_Notification przed wykonaniem początkowej enumeracji. Uzgodnij powiadomienia z początkową listą i obsłuż duplikaty, ponieważ przychodzący interfejs może pojawić się w obu. Zwolnij rejestrację powiadomień za pomocą CM_Unregister_Notification po zakończeniu. Usuwanie urządzenia może nadal kolidować z otwarciem ścieżki lub wykonaniem operacji we/wy.
Przykładowy kod: wyliczanie dysków
Note
Ponawianie próby obsługuje zmiany między zapytaniem rozmiaru i pobieraniem listy; nie gwarantuje ewentualnego powodzenia ani ciągłej dostępności zwróconych urządzeń. Przykład ponawia próbę CR_BUFFER_SMALL bez ograniczenia liczby prób, więc ponowne pojawianie się interfejsu może teoretycznie powodować ponawianie prób w nieskończoność. Inne niepowodzenia są zgłaszane i powodują zakończenie wyliczania.
#define INITGUID
#include <windows.h>
#include <ntddstor.h> // GUID_DEVINTERFACE_DISK
#include <cfgmgr32.h>
#include <stdio.h>
#include <stdlib.h> // malloc, free
#include <wchar.h> // wcslen
#pragma comment(lib, "cfgmgr32.lib")
//
// Opens and closes the disk using its device interface path.
// Zero desired access is intentional: this sample does not read or write data.
// When extending it, request the access required by the intended operation:
// GENERIC_READ for reads, GENERIC_WRITE for writes, and the access required
// by the specific IOCTL. Applicable device permissions also apply.
//
static void
ProcessDisk(
const wchar_t* DevicePath
)
{
HANDLE handle;
handle = CreateFileW(
DevicePath,
0, // No data read/write access requested.
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
0,
NULL
);
if (handle == INVALID_HANDLE_VALUE)
{
wprintf(L" open failed (%lu): %s\n", GetLastError(), DevicePath);
return;
}
// TODO: perform a supported query whose access requirements are satisfied
// by this handle. Adjust the CreateFileW access argument before adding
// operations that require read or write access.
CloseHandle(handle);
}
int
wmain(
void
)
{
wchar_t* list;
CONFIGRET cr;
ULONG len;
DWORD index;
len = 0;
RetryEnumeration:
//
// Select currently enabled disk device interfaces.
// This does not indicate the disk's online/offline state.
//
cr = CM_Get_Device_Interface_List_SizeW(
&len,
(LPGUID)&GUID_DEVINTERFACE_DISK,
NULL,
CM_GET_DEVICE_INTERFACE_LIST_PRESENT
);
if (cr != CR_SUCCESS || len == 0)
{
wprintf(L"CM_Get_Device_Interface_List_SizeW failed: 0x%lx\n", cr);
return 1;
}
//
// The result is a REG_MULTI_SZ style buffer: a contiguous run of
// NUL-terminated device paths, terminated by an extra empty string.
// 'len' is expressed in characters (including all NULs), so size the
// allocation in wchar_t units, not bytes.
//
list = (wchar_t*)malloc((size_t)len * sizeof(wchar_t));
if (list == NULL)
{
wprintf(L"Out of memory allocating %lu characters\n", len);
return 1;
}
cr = CM_Get_Device_Interface_ListW(
(LPGUID)&GUID_DEVINTERFACE_DISK,
NULL,
list,
len,
CM_GET_DEVICE_INTERFACE_LIST_PRESENT
);
if (cr == CR_BUFFER_SMALL)
{
// An interface may have arrived after the size query.
free(list);
goto RetryEnumeration;
}
if (cr != CR_SUCCESS)
{
wprintf(L"CM_Get_Device_Interface_ListW failed: 0x%lx\n", cr);
free(list);
return 1;
}
//
// Walk the multi-string buffer, one NUL-terminated device path per
// iteration, stopping at the empty string that terminates the list.
// 'list' is guaranteed NUL-terminated by the API contract, so this
// cannot run past the allocation.
//
index = 0;
for (wchar_t* current = list; *current != L'\0'; current += wcslen(current) + 1)
{
wprintf(L"[%lu] %s\n", index, current);
ProcessDisk(current);
index++;
}
free(list);
return 0;
}
Treści powiązane
- Wyliczanie zainstalowanych interfejsów urządzeń
- CM_Get_Device_Interface_ListW
- CM_Get_Device_Interface_List_SizeW
- IOCTL_STORAGE_GET_DEVICE_NUMBER
- IOCTL_STORAGE_QUERY_PROPERTY
- GUID_DEVINTERFACE_DISK
- IoGetDeviceInterfaces (odpowiednik trybu jądra)
- CreateFileW: żądane prawa dostępu
- Definiowanie kodów kontroli we/wy: wskazówki dotyczące ustawiania bitów dostępu
- CM_Register_Notification: kolejność rejestracji i początkowe wyliczenie