首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 組合語言

DeviceIoControl 實戰系列(五):透過 GUID 列舉系統已安裝儲存裝置並查詢屬性

     編輯:組合語言

當裝置路徑未知時,可透過裝置介面 GUID 列舉系統現有儲存裝置。本文示範 SetupAPI 列舉裝置路徑、以 IOCTL_STORAGE_QUERY_PROPERTY 取得廠商 ID、產品 ID、序號、總線類型等詳細屬性,解決「不知路徑如何開啟裝置」的核心問題。

核心流程:GUID → 裝置路徑 → 開啟 → IOCTL

1. 定義儲存裝置類別 GUID


DEFINE_GUID(GUID_DEVINTERFACE_DISK, 0x53f56307L, 0xb6bf, 0x11d0,
    0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b);

2. SetupAPI 列舉裝置介面詳情


int GetDevicePath(LPGUID lpGuid, LPTSTR* pszDevicePath) {
    HDEVINFO hDevInfo = SetupDiGetClassDevs(lpGuid, NULL, NULL,
        DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
    SP_DEVICE_INTERFACE_DATA ifData = {sizeof(SP_DEVICE_INTERFACE_DATA)};
    PSP_DEVICE_INTERFACE_DETAIL_DATA pDetail = (PSP_DEVICE_INTERFACE_DETAIL_DATA)
        GlobalAlloc(LMEM_ZEROINIT, 1024);
    pDetail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);

    int nCount = 0; BOOL bResult = TRUE;
    while (bResult) {
        bResult = SetupDiEnumDeviceInterfaces(hDevInfo, NULL, lpGuid,
            nCount, &ifData);
        if (bResult) {
            bResult = SetupDiGetInterfaceDeviceDetail(hDevInfo, &ifData,
                pDetail, 1024, NULL, NULL);
            if (bResult) {
                strcpy(pszDevicePath[nCount], pDetail->DevicePath);
                nCount++;
            }
        }
    }
    GlobalFree(pDetail);
    SetupDiDestroyDeviceInfoList(hDevInfo);
    return nCount;
}

需連結 setupapi.lib,包含 initguid.h, setupapi.h。

3. 取得路徑特徵

路徑格式範例:

\\?\ide#diskmaxtor_2f040j0__________________________vam51jj0#3146563447534558202020202020202020202020#{53f56307-b6bf-11d0-94f2-00a0c91efb8b}

編碼包含:匯流排類型 (IDE/SCSI/USB)、產品型號、韌體版本、序號、GUID。無標準解析規則,僅供人工識別。

IOCTL_STORAGE_QUERY_PROPERTY 取得裝置描述符

關鍵結構定義


typedef enum _STORAGE_BUS_TYPE { BusTypeUnknown=0, BusTypeScsi, BusTypeAtapi,
    BusTypeAta, BusType1394, BusTypeSsa, BusTypeFibre, BusTypeUsb, BusTypeRAID } STORAGE_BUS_TYPE;

typedef struct _STORAGE_PROPERTY_QUERY {
    STORAGE_PROPERTY_ID PropertyId;  // StorageDeviceProperty / StorageAdapterProperty
    STORAGE_QUERY_TYPE QueryType;    // PropertyStandardQuery / PropertyExistsQuery ...
    UCHAR AdditionalParameters[1];
} STORAGE_PROPERTY_QUERY;

typedef struct _STORAGE_DEVICE_DESCRIPTOR {
    ULONG Version, Size;
    UCHAR DeviceType, DeviceTypeModifier;
    BOOLEAN RemovableMedia, CommandQueueing;
    ULONG VendorIdOffset, ProductIdOffset, ProductRevisionOffset, SerialNumberOffset;
    STORAGE_BUS_TYPE BusType;
    ULONG RawPropertiesLength;
    UCHAR RawDeviceProperties[1];  // 緊接著 VendorId/ProductId/Revision/SerialNumber 字串
} STORAGE_DEVICE_DESCRIPTOR;

呼叫範例


BOOL GetDriveProperty(HANDLE hDevice, PSTORAGE_DEVICE_DESCRIPTOR pDesc) {
    STORAGE_PROPERTY_QUERY q = {StorageDeviceProperty, PropertyStandardQuery};
    DWORD dwOut;
    return DeviceIoControl(hDevice, IOCTL_STORAGE_QUERY_PROPERTY,
        &q, sizeof(q), pDesc, pDesc->Size, &dwOut, NULL);
}

呼叫後需根據 Offset 從 RawDeviceProperties 解析字串 (ANSI/Unicode 視驅動而定)。

已知問題與疑問

  • 光碟機、USB 外接硬碟常回傳空序號/產品 ID,但裝置路徑中卻包含該資訊 — 驅動實作差異所致。
  • 序號在描述符中常為十六進位編碼 (如 31465634475345582020...),非原始 ASCII — 可能為驅動轉換格式。

歡迎專家補充驅動層面的解釋。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved