Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
GUID_DEVINTERFACE_DISK mengidentifikasi kelas antarmuka perangkat disk. Driver kelas disk yang disediakan sistem mendaftarkan instans kelas ini untuk disk yang mereka ekspos. Mendaftar instans yang diaktifkan adalah cara stack-agnostic untuk menemukan jalur perangkat disk: baik tumpukan warisan maupun tumpukan NVMe Asli mengekspos kelas antarmuka ini.
Inilah sebabnya mengapa Anda harus menghitung GUID antarmuka daripada menjadikan GUID kelas pengaturan sebagai acuan, seperti GUID_DEVCLASS_DISKDRIVE, yang tidak dijamin sebagai stack-agnostic.
GUID antarmuka vs. GUID kelas perangkat
GUID_DEVINTERFACE_DISK dan GUID_DEVCLASS_DISKDRIVE menjawab pertanyaan yang berbeda dan tidak dapat dipertukarkan:
-
GUID_DEVINTERFACE_DISKmengidentifikasi kelas antarmuka, bukan path perangkat individual. Mencacah instans yang diaktifkan mengembalikan jalur tautan simbolis yang dapat diteruskan aplikasi ke CreateFileW. Handel yang dihasilkan dapat digunakan untuk operasi yang didukung oleh disk target, tunduk pada hak akses yang diminta dan izin yang berlaku. Jalur enumerasi bukan jaminan bahwa membuka disk akan berhasil: perangkat dapat dihapus atau menjadi tidak tersedia sebelum permintaan pembukaan selesai. -
GUID_DEVCLASS_DISKDRIVEadalah kelas penyiapan perangkat yang digunakan oleh PnP/SetupAPI untuk penginstalan dan klasifikasi perangkat, seperti penginstalan driver, pengelompokan Device Manager, pencocokan INF, dan tugas layanan serupa. Instans perangkat milik kelas penyiapan ini tidak dijamin untuk mengekspos antarmuka yang dapat Anda buka, dan mencacah berdasarkan kelas penyiapan tidak mengatakan apa pun tentang antarmuka fungsional mana, jika ada, yang saat ini diekspos oleh instans perangkat tersebut. - Tumpukan disk warisan (
disk.sys/classpnp.sys) menggunakanGUID_DEVCLASS_DISKDRIVEkelas penyiapan, sementara tumpukan NVMe Asli (nvmedisk.sys) menggunakan kelas penyiapannya sendiri yang berbeda,{75416e63-5912-4dfa-ae8f-3efaccaffb14}. Karena itu, mendaftar hanyaGUID_DEVCLASS_DISKDRIVEakan melewatkan setiap disk yang dikelola oleh tumpukan NVMe Asli.GUID_DEVINTERFACE_DISKtidak memiliki kesenjangan ini, karena kedua stack mendaftarkan antarmuka yang sama untuk setiap disk yang mereka kelola.
Cakupan enumerasi
Sampel ini melakukan enumerasi satu kali antarmuka perangkat disk yang saat ini diaktifkan. Ini tidak mencantumkan volume atau huruf drive, dan daftar yang dikembalikan bukan inventarium yang terus dipertahankan.
CM_GET_DEVICE_INTERFACE_LIST_PRESENT menyeleksi antarmuka yang ada/diaktifkan. Ini tidak menunjukkan apakah disk berstatus online di Manajemen Disk.
Untuk aplikasi jangka panjang yang melacak penyambungan dan pelepasan perangkat, daftarkan pemberitahuan antarmuka perangkat dengan CM_Register_Notification sebelum melakukan enumerasi awal. Rekonsiliasi pemberitahuan dengan daftar awal dan tangani duplikat, karena interface yang masuk dapat muncul di keduanya. Batalkan pendaftaran pemberitahuan dengan CM_Unregister_Notification setelah selesai. Penghapusan perangkat masih dapat berbenturan dengan membuka path atau melakukan I/O.
Kode sampel: mendaftar disk
Note
Mencoba kembali menangani perubahan antara kueri ukuran dan pengambilan daftar; ini tidak menjamin keberhasilan akhir atau ketersediaan berkelanjutan dari perangkat yang dikembalikan. Sampel mencoba ulang CR_BUFFER_SMALL tanpa batas upaya, sehingga munculnya antarmuka berulang secara teoritis dapat membuatnya terus mencoba ulang tanpa batas waktu. Kegagalan lain dilaporkan dan enumerasi dihentikan.
#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;
}
Konten terkait
- Mendaftar antarmuka perangkat yang terinstal
- CM_Get_Device_Interface_ListW
- CM_Get_Device_Interface_List_SizeW
- IOCTL_STORAGE_GET_DEVICE_NUMBER
- IOCTL_STORAGE_QUERY_PROPERTY
- GUID_DEVINTERFACE_DISK
- IoGetDeviceInterfaces (padanan mode kernel)
- CreateFileW: hak akses yang diminta
- Menentukan kode kontrol I/O: panduan untuk mengatur bit Access
- CM_Register_Notification: urutan pendaftaran dan enumerasi awal