1

I am trying to get paths of all devices with device interfaces, but when I call SetupDiEnumDeviceInterfaces I get 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;
}

I've looked into this answer, but it does not work for me, since it uses a GUID for usb devices. In My case the desired devices may be connected not only via USB, but also via PCI and PCI express.

I need those paths to use in CreateFile. Have I taken an inappropriate approach? Are there alternatives?

Sergey Kolesnik
  • 3,009
  • 1
  • 8
  • 28
  • How do you acquire hdevinfo? – Simon Mourier Jun 19 '20 at 21:31
  • @SimonMourier what do you mean? I use `SetupDiGetClassDevs` as it can be seen from the code section – Sergey Kolesnik Jun 19 '20 at 21:33
  • oops. sorry, scrollbar issue :) – Simon Mourier Jun 19 '20 at 21:35
  • You could use property keys which may be easier since Vista, as I commented here: https://stackoverflow.com/questions/62266445/how-to-get-extended-port-information-when-enumerating-ports-using-windows-api#comment110183366_62266445 and my code is still here: https://pastebin.com/raw/TtVFYMpT – Simon Mourier Jun 19 '20 at 22:06
  • *I need those paths to use in CreateFile* - and what sense in this ? assume you open file on unknown device - what you will be do next ? and why you want exactly interfaces enumerate ? why not all pdo names, which also can be used for open file on device. formal exist 2 way - call `CM_Enumerate_Classes` with `CM_ENUMERATE_CLASSES_INTERFACE` and then use returned guid in call `CM_Get_Device_Interface_ListW` or possible retrieves a list of device instance IDs with `CM_Get_Device_ID_ListW` – RbMm Jun 21 '20 at 12:29
  • and then for device ID every call `CM_Locate_DevNodeW` and `CM_Get_DevNode_PropertyW` with `DEVPKEY_Device_PDOName` – RbMm Jun 21 '20 at 12:29
  • @RbMm I don't want 'exactly interfaces', I want device paths that I can use to open a device. I just happened to find out that SetupDi functions can be helpful with that. You may post an answer with a working (or at least reproducible, with links to functions' reference) example of enumerating pdo names. That would be very helpful indeed. – Sergey Kolesnik Jun 21 '20 at 12:41
  • yes, i of course can post both variant of working code, but still not understand for what you need try open unknown device – RbMm Jun 21 '20 at 12:44
  • @RbMm I don't want to open an unknown device. I need to find out if there are particular devices present and store that information in a vector. To be precise, I have an abstraction for Arinc429 and various types of devices that might be connected to the machine. For each device that happens to be an Arinc429 (PCI, PCI express or USB) I want to create an instance using Arinc429Factory. Currently I use some of GUIDs that have been provided by the driver distributors, but I also want to try finding out devices names without using GUIDs. – Sergey Kolesnik Jun 21 '20 at 12:58
  • and how you can know Arinc429 this or not ? you must know at begin it interface guid or some else property, how you can detect – RbMm Jun 21 '20 at 13:04
  • @RbMm I've just looked up the pdo of one instance and you are right - there s no way of deducing if it is Arinc429 or not just from the pdo name. However, there is some way to get it from Device instance path. And it is absolutely possible to distinguish it by Display name. – Sergey Kolesnik Jun 21 '20 at 13:21

1 Answers1

2

we can retrieves a list of device instance IDs for the local computer's device instances with CM_Get_Device_ID_ListW function

then for every ID obtains a device instance handle to the device by CM_Locate_DevNodeW

and then retrieves a device instance property's with CM_Get_DevNode_PropertyW. for example DEVPKEY_NAME and DEVPKEY_Device_PDOName - name of the physical device object (PDO). this name we can use inside 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);

}
RbMm
  • 31,280
  • 3
  • 35
  • 56