Kommentar
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
GUID_DEVINTERFACE_DISK identifierar diskenhetsgränssnittsklassen. De systemlevererade diskklassdrivrutinerna registrerar instanser av den här klassen för de diskar som de exponerar. Att räkna upp dess aktiverade instanser är det stackagnostiska sättet att identifiera diskenhetssökvägar: både den äldre stacken och Native NVMe-stacken exponerar den här gränssnittsklassen.
Därför bör du räkna upp gränssnittets GUID i stället för att utgå från ett installationsklass-GUID, till exempel GUID_DEVCLASS_DISKDRIVE, som inte garanteras vara stackagnostisk.
Gränssnitts-GUID jämfört med GUID för enhetsklass
GUID_DEVINTERFACE_DISK och GUID_DEVCLASS_DISKDRIVE besvara olika frågor och är inte utbytbara:
-
GUID_DEVINTERFACE_DISKidentifierar en gränssnittsklass, inte en enskild enhetssökväg. Om du räknar upp dess aktiverade instanser returneras symboliska länksökvägar som program kan använda med CreateFileW. Det resulterande handtaget kan användas för åtgärder som stöds av måldisken, med förbehåll för de begärda åtkomsträttigheterna och tillämpliga behörigheter. En uppräknad sökväg är inte en garanti för att det går att öppna disken: enheten kan tas bort eller bli otillgänglig innan begäran om att öppna disken har slutförts. -
GUID_DEVCLASS_DISKDRIVEär en enhetsinstallationsklass som används av PnP/SetupAPI för enhetsinstallation och -klassificering, till exempel drivrutinsinstallation, Správca zariadení gruppering, INF-matchning och liknande serviceuppgifter. En enhetsinstans som tillhör den här installationsklassen är inte garanterad att exponera ett gränssnitt som du kan öppna, och uppräkning av installationsklass säger ingenting om vilka funktionella gränssnitt, om några, som enhetsinstansen för närvarande exponerar. - Den äldre diskstacken (
disk.sys/classpnp.sys) använder installationsklassenGUID_DEVCLASS_DISKDRIVE, medan den inbyggda NVMe-stacken (nvmedisk.sys) använder sin egen, olika installationsklass,{75416e63-5912-4dfa-ae8f-3efaccaffb14}. Att bara räkna uppGUID_DEVCLASS_DISKDRIVEskulle därför missa varje disk som hanteras av den interna NVMe-stacken.GUID_DEVINTERFACE_DISKhar inte det här gapet eftersom båda stackarna registrerar samma gränssnitt för varje disk som de hanterar.
Uppräkningsomfång
Det här exemplet utför en engångsinventering av för närvarande aktiverade diskenhetsgränssnitt. Den räknar inte upp volymer eller enhetsbeteckningar och den returnerade listan är inte en kontinuerligt underhållen inventering.
CM_GET_DEVICE_INTERFACE_LIST_PRESENT väljer tillgängliga/aktiverade gränssnitt. Det anger inte om en disk är online i Diskhantering.
För ett långvarigt program som spårar ankomster och borttagningar registrerar du enhetsgränssnittsaviseringar med CM_Register_Notification innan du utför den första uppräkningen. Jämför notiser med den ursprungliga listan och hantera dubbletter, eftersom ett ankommande gränssnitt kan visas i båda. Släpp meddelanderegistreringen med CM_Unregister_Notification när du är klar. Borttagning av enhet kan fortfarande kollidera med att öppna en sökväg eller utföra I/O.
Exempelkod: räkna upp diskar
Note
Att försöka igen hanterar ändringar mellan storleksfrågan och listhämtningen. Det garanterar inte att det till slut lyckas eller att de returnerade enheterna fortsätter att vara tillgängliga. Exemplet försöker igen CR_BUFFER_SMALL utan en försöksgräns, så att upprepade gränssnittsanslutningar teoretiskt sett kan få det att fortsätta försöka igen på obestämd tid. Andra fel rapporteras och avslutar uppräkningen.
#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;
}
Relaterat innehåll
- Räkna upp installerade enhetsgränssnitt
- CM_Get_Device_Interface_ListW
- CM_Get_Device_Interface_List_SizeW
- IOCTL_STORAGE_GET_DEVICE_NUMBER
- IOCTL_STORAGE_QUERY_PROPERTY
- GUID_DEVINTERFACE_DISK
- IoGetDeviceInterfaces (motsvarighet i kernelläge)
- CreateFileW: begärda åtkomsträttigheter
- Definiera I/O-kontrollkoder: vägledning för att ange åtkomstbitar
- CM_Register_Notification: registreringsordning och inledande uppräkning