Get device instance DWORD from device instance path string

3.6k Views Asked by At

I get an device instance path like

L"\\\\?\\USB#VID_0403&PID_6001#6&2cc2d230&0&2#{219d0508-57a8-4ff5-97a1-bd86587c6c7e}"

from IWDFRemoteInterfaceInitialize::RetrieveSymbolicLink.
But for CM_Get_Parent I need the DEVINST/DWORD of the device which drives me crazy.
I've tried for example

instancePath = L"\\\\?\\USB#VID_0403&PID_6001#6&2cc2d230&0&2#{219d0508-57a8-4ff5-97a1-bd86587c6c7e}";
HDEVINFO hinfo = SetupDiGetClassDevs(NULL, instancePath, NULL, DIGCF_DEVICEINTERFACE | DIGCF_ALLCLASSES);

and some other SetupDi... voodoo with no success. Any help is highly appreciated because -as mentioned- I haven't been able to get around this madness for hours now and though there are dozens of examples for the other way round (devid->instance path) I haven't found any for instance path->DEVINST.

2

There are 2 best solutions below

1
gog On

As you said, there's not a direct way.

However, you should be able to get a Device Instance ID from your Device Path / Device Interface ID by means of some string editing, following the below steps:

  1. Remove entirely the starting \\\\?\\ part, until the USB.
  2. Remove entirely the last {...} part
  3. Replace # with \

Starting from

"\\\\?\\USB#VID_0403&PID_6001#6&2cc2d230&0&2#{219d0508-57a8-4ff5-97a1-bd86587c6c7e}"

you should now have

"USB\VID_0403&PID_6001\6&2cc2d230&0&2\"

which should be a valid Device Instance ID. If it's not, try removing the last "\" too.

Then, you can feed this to CM_Locate_DevNode() and get the wanted DEVINST.

0
alexmerry On

While modifying the path will probably work, the Windows docs explicitly say that you should not parse device paths.

You can do it with the CfgMgr32 API, though, using CM_Get_Device_Interface_PropertyW () and DEVPKEY_Device_InstanceId:

#include <cfgmgr32.h>
#include <initguid.h> // needed for devpkey.h to parse properly
#include <devpkey.h>

#include <cassert>
#include <string>
#include <vector>

/*
 *   @brief The following retrieves the Device Instance ID from the main device path.
 *   @param device_path A device path that has the form of the following:
 *                      \\?\usb#vid_[VENDOR_ID]&pid_[PRODUCT_ID]#INSTANCE_ID#{[DEVICE_INTERFACE_GUID]}
 *
 *                      Where the following components are described as:
 *                          1. VENDOR_ID             - The vendor ID of the device.
 *                          2. PRODUCT_ID            - The product ID of the device.
 *                          3. INSTANCE_ID           - The unique ID generated when the device connects to the host.
 *                          4. DEVICE_INTERFACE_GUID - The GUID that describes the interface of the device.
 *                                                     This is NOT the same as the "Device Class GUID."
 *   @return The Device Instance ID (linked below). A Device Instance ID has the form of:
 *           <device-id>\<instance-id>
 *
 *           Example: USB\VID_2109&PID_0813\7&3981c8d6&0&2
 *   @see https://learn.microsoft.com/en-us/windows-hardware/drivers/install/device-instance-ids
 *   @see https://learn.microsoft.com/en-us/windows/win32/api/cfgmgr32/nf-cfgmgr32-cm_get_device_interface_propertyw
 */
std::wstring map_path (LPCWSTR device_path) {
    ULONG buf_size = 0;
    DEVPROPTYPE type;
    CM_Get_Device_Interface_PropertyW(
        device_path, &DEVPKEY_Device_InstanceId, &type,
        nullptr, &buf_size, 0);

    std::vector<BYTE> buffer(buf_size);
    auto result = CM_Get_Device_Interface_PropertyW(
        device_path, &DEVPKEY_Device_InstanceId, &type,
        buffer.data(), &buf_size, 0);

    assert(result == CR_SUCCESS);
    assert(type == DEVPROP_TYPE_STRING);

    // buffer will be null-terminated
    return reinterpret_cast<wchar_t*>(buffer.data());
}