GUID_DEVINTERFACE_DISK 디스크 디바이스 인터페이스 클래스를 식별합니다. 시스템 제공 디스크 클래스 드라이버는 노출하는 디스크에 대해 이 클래스의 인스턴스를 등록합니다. 해당 인터페이스 클래스의 사용하도록 설정된 인스턴스를 열거하는 것은 디스크 디바이스 경로를 검색하는 스택에 구애받지 않는 방법입니다. 레거시 스택과 네이티브 NVMe 스택은 모두 이 인터페이스 클래스를 노출합니다.
따라서 인터페이스 GUID를 열거해야 하며, GUID_DEVCLASS_DISKDRIVE 같은 설치 클래스 GUID를 키오프해서는 안 됩니다. 이는 스택에 구애받지 않는다고 보장되지 않습니다.
인터페이스 GUID 대 디바이스 클래스 GUID
GUID_DEVINTERFACE_DISK 및 GUID_DEVCLASS_DISKDRIVE는 서로 다른 질문에 답하며 서로 교환할 수 없습니다.
-
GUID_DEVINTERFACE_DISK는 개별 디바이스 경로가 아닌 인터페이스 클래스를 식별합니다. 활성화된 인스턴스를 열거하면 애플리케이션이 CreateFileW에 전달할 수 있는 기호 링크 경로가 반환됩니다. 결과 핸들은 요청된 액세스 권한 및 해당 권한에 따라 대상 디스크에서 지원하는 작업에 사용할 수 있습니다. 열거형 경로는 디스크를 여는 것이 성공한다는 보장이 아닙니다. 열기 요청이 완료되기 전에 디바이스가 제거되거나 사용할 수 없게 될 수 있습니다. -
GUID_DEVCLASS_DISKDRIVE는 드라이버 설치, 장치 관리자 그룹화, INF 일치 및 유사한 서비스 작업과 같은 디바이스 설치 및 분류를 위해 PnP/SetupAPI에서 사용하는 디바이스 설정 클래스입니다. 이 설정 클래스에 속하는 디바이스 인스턴스는 열 수 있는 인터페이스를 노출하도록 보장되지 않으며, 설치 클래스를 통해 열거하면 해당 디바이스 인스턴스가 현재 노출하는 기능 인터페이스(있는 경우)에 대해 아무 말도 하지 않습니다. - 레거시 디스크 스택(
disk.sys/classpnp.sys)은GUID_DEVCLASS_DISKDRIVE설정 클래스를 사용하는 반면, 네이티브 NVMe 스택(nvmedisk.sys)은 고유한 다른 설정 클래스인{75416e63-5912-4dfa-ae8f-3efaccaffb14}를 사용합니다. 따라서GUID_DEVCLASS_DISKDRIVE만 열거하면 네이티브 NVMe 스택에서 관리하는 모든 디스크가 누락됩니다.GUID_DEVINTERFACE_DISK는 두 스택이 관리하는 각 디스크에 대해 동일한 인터페이스를 등록하므로 이러한 차이가 없습니다.
열거형 범위
이 샘플에서는 현재 사용하도록 설정된 디스크 디바이스 인터페이스의 일회성 열거를 수행합니다. 볼륨이나 드라이브 문자를 열거하지 않으며 반환된 목록은 지속적으로 유지 관리되는 인벤토리가 아닙니다.
CM_GET_DEVICE_INTERFACE_LIST_PRESENT는 현재/활성화된 인터페이스를 선택합니다. 디스크 관리에서 디스크가 온라인인지 여부는 나타내지 않습니다.
도착 및 제거를 추적하는 장기 실행 애플리케이션의 경우 초기 열거를 수행하기 전에 CM_Register_Notification 디바이스 인터페이스 알림을 등록합니다. 도착하는 인터페이스가 둘 다에 나타날 수 있으므로 알림을 초기 목록과 조정하고 중복 항목을 처리합니다. 완료되면 CM_Unregister_Notification 사용하여 알림 등록을 해제합니다. 디바이스 제거는 경로를 열거나 I/O를 수행하는 작업과도 계속 경합할 수 있습니다.
샘플 코드: 디스크 열거
메모
다시 시도하면 크기 쿼리와 목록 검색 간의 변경 내용이 처리됩니다. 반환된 디바이스의 결국 성공 또는 지속적인 가용성을 보장하지는 않습니다. 샘플은 CR_BUFFER_SMALL 시도 제한 없이 재시도하므로, 인터페이스 이벤트가 반복적으로 발생하면 이론적으로 무기한 재시도를 계속할 수 있습니다. 다른 오류는 보고되고 열거를 종료합니다.
#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;
}
관련 콘텐츠
- 설치된 디바이스 인터페이스 열거
- CM_Get_Device_Interface_ListW
- CM_Get_Device_Interface_List_SizeW
- IOCTL_STORAGE_GET_DEVICE_NUMBER
- IOCTL_STORAGE_QUERY_PROPERTY
- GUID_DEVINTERFACE_DISK
- IoGetDeviceInterfaces (커널 모드 버전)
- CreateFileW: 요청된 액세스 권한
- I/O 컨트롤 코드 정의: Access 비트를 설정하기 위한 지침
- CM_Register_Notification: 등록 순서 지정 및 초기 열거