【问题标题】:Enumerate all device paths枚举所有设备路径
【发布时间】:2020-10-10 01:23:58
【问题描述】:

我正在尝试获取具有设备接口的所有设备的路径,但是当我调用SetupDiEnumDeviceInterfaces 时,我得到了ERROR_NO_MORE_ITEMS


#include <windows.h>
#include <setupapi.h>

#include <iostream>
#include <string>
#include <vector>

int main(int argc, const char **argv)
{

    HDEVINFO hdevinfo = SetupDiGetClassDevs(0, 0, 0, DIGCF_ALLCLASSES |
            DIGCF_PRESENT |
            DIGCF_DEVICEINTERFACE);
    if (hdevinfo == INVALID_HANDLE_VALUE)
    {
        std::cerr << "Failed to get device information set" << std::endl;
        return -1;
    }

    SP_DEVINFO_DATA devinfoData{sizeof(SP_DEVINFO_DATA)};
    SP_DEVICE_INTERFACE_DATA deviceInterfaceData{sizeof(SP_DEVICE_INTERFACE_DATA)};

    std::vector<std::string> devicePaths{};
    devicePaths.reserve(512);

    DWORD index = 0;

    while (SetupDiEnumDeviceInfo(hdevinfo, index, &devinfoData))
    {
        if (!SetupDiEnumDeviceInterfaces(hdevinfo, &devinfoData, &devinfoData.ClassGuid, index, &deviceInterfaceData))
        {
            DWORD error = GetLastError();
            std::cout << "Error: " << error << std::endl; // always get 259
            ++index;
            continue;
        }

        DWORD reqSize = 0;
        SetupDiGetDeviceInterfaceDetail(hdevinfo, &deviceInterfaceData, 0, 0, &reqSize, 0);
        PSP_INTERFACE_DEVICE_DETAIL_DATA pDetailData = PSP_INTERFACE_DEVICE_DETAIL_DATA(new char[reqSize]);
        pDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);

        if (SetupDiGetDeviceInterfaceDetail(hdevinfo, &deviceInterfaceData, pDetailData, reqSize, 0, 0));
            devicePaths.push_back(pDetailData->DevicePath);

        delete [] pDetailData;

        ++index;
    }

    SetupDiDestroyDeviceInfoList(hdevinfo);

    return 0;
}

我查看了this answer,但它对我不起作用,因为它使用 USB 设备的 GUID。在我的情况下,所需的设备不仅可以通过 USB 连接,还可以通过 PCI 和 PCI express 连接。

我需要在CreateFile 中使用这些路径。 我是否采取了不恰当的方法?有替代品吗?

【问题讨论】:

  • 如何获取hdevinfo?
  • @SimonMourier 你是什么意思?我使用SetupDiGetClassDevs,从代码部分可以看出
  • 哎呀。抱歉,滚动条问题:)
  • 您可以使用自 Vista 以来可能更容易的属性键,正如我在这里评论的:stackoverflow.com/questions/62266445/… 我的代码仍然在这里:pastebin.com/raw/TtVFYMpT
  • 我需要在 CreateFile 中使用这些路径 - 这有什么意义?假设您在未知设备上打开文件 - 接下来您将做什么?以及为什么要精确地枚举接口?为什么不是所有的 pdo 名称,也可以用于在设备上打开文件。正式存在 2 方式 - 使用 CM_ENUMERATE_CLASSES_INTERFACE 调用 CM_Enumerate_Classes,然后在调用 CM_Get_Device_Interface_ListW 中使用返回的 guid,或者可能使用 CM_Get_Device_ID_ListW 检索设备实例 ID 列表

标签: c++ winapi device-driver


【解决方案1】:

我们可以使用CM_Get_Device_ID_ListW函数为本地计算机的设备实例检索设备列表instance IDs

那么对于每个ID,通过CM_Locate_DevNodeW获取设备的一个设备实例句柄

然后使用CM_Get_DevNode_PropertyW 检索设备实例属性。例如 DEVPKEY_NAMEDEVPKEY_Device_PDOName - 物理设备对象 (PDO) 的名称。这个名字我们可以在NtOpenFile中使用

volatile UCHAR guz = 0;

void ProcessList(PZZWSTR pDeviceID)
{
    ULONG cb = 0, rcb = 0x80;
    CONFIGRET cr;
    PVOID stack = alloca(guz);

    union {
        PVOID buf;
        PBYTE PropertyBuffer;
    };

    HANDLE hFile;
    IO_STATUS_BLOCK iosb;
    UNICODE_STRING ObjectName;
    OBJECT_ATTRIBUTES oa = { sizeof(oa), 0, &ObjectName };

    do
    {
        DEVINST dnDevInst;

        if (CM_Locate_DevNodeW(&dnDevInst, pDeviceID, CM_LOCATE_DEVNODE_NORMAL) == CR_SUCCESS)
        {
            DbgPrint("\n%S:\t", pDeviceID);

            DEVPROPTYPE PropertyType;

            static const DEVPROPKEY PropertyKeys[] = { DEVPKEY_Device_PDOName, DEVPKEY_NAME };
            static const PCSTR Names[] = { "PDOName", "FriendlyName" };

            ULONG i = _countof(PropertyKeys);

            do 
            {
                const DEVPROPKEY* PropertyKey = &PropertyKeys[--i];
                PCSTR Name = Names[i];

                do 
                {
                    if (cb < rcb)
                    {
                        cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack);
                    }

                    cr = CM_Get_DevNode_PropertyW(dnDevInst, PropertyKey, 
                        &PropertyType, PropertyBuffer, &(rcb = cb), 0);

                    if (cr == CR_SUCCESS && PropertyType == DEVPROP_TYPE_STRING)
                    {
                        DbgPrint("[%s=%S]\t", Name, PropertyBuffer);

                        if (!i)
                        {
                            RtlInitUnicodeString(&ObjectName, (PWSTR)PropertyBuffer);
                            NTSTATUS status = NtOpenFile(&hFile, FILE_READ_ATTRIBUTES, &oa, &iosb, FILE_SHARE_VALID_FLAGS, 0);
                            if (0 <= status)
                            {
                                NtClose(hFile);
                            }
                            DbgPrint("=%x", status);
                        }
                    }

                } while (cr == CR_BUFFER_SMALL);

            } while (i);
        }

    } while (*(pDeviceID += wcslen(pDeviceID) + 1));
}

void cccm()
{
    CONFIGRET cr;
    PZZWSTR pDeviceID;
    ULONG ulLen;

    do 
    {
        if (CM_Get_Device_ID_List_SizeW(&ulLen, 0, CM_GETIDLIST_FILTER_PRESENT) != CR_SUCCESS || ulLen <= 1)
        {
            break;
        }

        if (pDeviceID = new WCHAR[ulLen])
        {
            if ((cr = CM_Get_Device_ID_ListW(0, pDeviceID, ulLen, CM_GETIDLIST_FILTER_PRESENT)) == CR_SUCCESS)
            {
                if (*pDeviceID) ProcessList(pDeviceID);
            }
            delete [] pDeviceID;
        }
        else
        {
            break;
        }

    } while (cr == CR_BUFFER_SMALL);

}

【讨论】:

    猜你喜欢
    • 2023-03-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-29
    • 1970-01-01
    相关资源
    最近更新 更多